I need a function (I named it
applyToEveryPair) that works on lists, e.g.
[x0,x1,x2,x3,...], and uses a function
f:: (a,a) -> [(a,a)]. For every (distinct) pair
i/=j of the list
I want all lists where
xi is replaced by
xj is replaced by
xik is the output of
This visualizes input and output
[a0, a1 ,a2 ,a3 ] -- input to applyToEveryPair | | | | v v f(a0, a1) =[(b0,b1),(c0,c1)] | | v v [b0, b1, a2, a3] -- to be included in output [c0, c1, a2, a3] -- to be included in output ... -- more output | | -- now combine (a3,a1) \ / \ / \/ /\ / \ f(a3, a1) = [(d3, d1)] \ / \/ /\ / \ / \ [a0, d1 ,a2 ,d3 ] -- to be included in output
A use case would be to input a matrix and compute all resulting matrices for every (pairwise) line swap (
f swaps lines), or, in my case, all possible move in a solitaire game from one stack of cards to another.
Long story, short code; This is how I do it so far:
applyToEveryPair :: ((a,a) -> [(a,a)]) -> [a] -> [[a]] applyToEveryPair f (xs) = do i<-[0..length xs - 1] j<-[0..length xs - 1] guard (i /= j) (x',y') <- f (xs !! i, xs !! j) return . setList i x' . setList j y' $ xs -- | setList n x xs replaces the nth element in xs by x setList :: Int -> a -> [a] -> [a] setList = go 0 where go _ _ _  =  go i n x' (x:xs) | i == n = x':xs | otherwise = x:(go (i+1) n x' xs)
I think comonads are overkill here, and I have not understood Lenses (yet), but have a vague feeling lenses apply here.
The solution I use feels not very haskellish. I want to know if this is a good way to write it, but especially the double use of
setList looks terrible to me. How to speed up / beautify this code?