Consider
filterM (\\x -> [True, False]) [1, 2, 3]
I just cannot understand the magic that Haskell does with this filterM
use ca
This is pretty straightforward, after we've put it all down on paper (someone smart once gave this advice: don't try doing it all in your head, put it all on paper!):
filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
filterM _ [] = return []
filterM p (x:xs) = do { flg <- p x
; ys <- filterM p xs
; return (if flg then x:ys else ys) }
-- filterM (\x -> [True, False]) [1, 2, 3]
g [x,y,z] = filterM (\x -> [True, False]) (x:[y,z])
= do {
flg <- (\x -> [True, False]) x
; ys <- g [y,z]
; return ([x | flg] ++ ys) }
= do {
flg <- [True, False] -- no `x` here!
; ys <- do { flg2 <- (\x -> [True, False]) y
; zs <- g [z]
; return ([y | flg2] ++ zs) }
; return ([x | flg] ++ ys) }
= do {
flg <- [True, False]
; flg2 <- [True, False]
; zs <- do { flg3 <- (\x -> [True, False]) z
; s <- g []
; return ([z | flg3] ++ s) }
; return ([x | flg] ++ [y | flg] ++ zs) }
= do {
flg <- [True, False]
; flg2 <- [True, False]
; flg3 <- [True, False]
; s <- return []
; return ([x | flg] ++ [y | flg2] ++ [z | flg3] ++ s) }
The unnesting of the nested do
blocks follows from the Monad laws.
Thus, in pseudocode:
filterM (\x -> [True, False]) [1, 2, 3]
=
for flg in [True, False]: -- x=1
for flg2 in [True, False]: -- y=2
for flg3 in [True, False]: -- z=3
yield ([1 | flg] ++ [2 | flg2] ++ [3 | flg3])