You have to desugar the notation. First start by writing down the types:
import Control.Arrow moves :: [(Integer, Integer) -> (Integer, Integer)] moves = do f <- [(+), subtract] g <- [(+), subtract] (x, y) <- [(1, 2), (2, 1)] [f x *** g y]
So we are in the [] (list) monad.
Lookup the definition of Monad []:
instance Monad [] where m >>= k = foldr ((++) . k) [] m m >> k = foldr ((++) . (\ _ -> k)) [] m return x = [x]
And translate the do notation to bind and return:
moves = [(+), subtract] >>= \f -> [(+), subtract] >>= \g -> [(1, 2), (2, 1)] >>= \(x,y) -> [f x *** g y]
Then, finally, rewrite the binds in terms of their definitions:
By return on list
moves = [(+), subtract] >>= \f -> [(+), subtract] >>= \g -> [(1, 2), (2, 1)] >>= \(x,y) -> return (f x *** g y)
Definition of >>=
moves = foldr ((++) . (\f -> [(+), subtract] >>= \g -> [(1, 2), (2, 1)] >>= \(x,y) -> return (f x *** g y) )) [] [(+), subtract]
Definition of >>=
moves = foldr ((++) . (\f -> foldr ((++) . (\g -> [(1, 2), (2, 1)] >>= \(x,y) -> return (f x *** g y)) ) [] [(+), subtract] )) [] [(+), subtract]
Definition of >>=
moves = foldr ((++) . (\f -> foldr ((++) . (\g -> foldr ((++) . (\(x,y) -> return (f x *** g y)) ) [] [(1, 2), (2, 1)] )) [] [(+), subtract] )) [] [(+), subtract]
Undo the return:
moves = foldr ((++) . (\f -> foldr ((++) . (\g -> foldr ((++) . (\(x,y) -> [f x *** g y]) ) [] [(1, 2), (2, 1)] )) [] [(+), subtract] )) [] [(+), subtract]
So you see its a nested fold over two element lists. Unfolding the folds is left as an exercise for the reader :)
moves = [f x *** g y | f <- [(+), subtract], g <- [(+), subtract], (x, y) <- [(1, 2), (2, 1)]][x] = return x.