Indeed, it's not possible to directly apply the associative law, because of the scope of x
in the original expression:
import Control.Monad (liftM)
test = let m = [1,2]
ys = [4, 5, 6]
in m >>= (\x -> ys >>= (\y -> return (x, y)))
However, we can reduce the scope of x
if we include it into the result of the first monadic computation. Instead of returning [Int]
in x -> ys
, we'll use \x -> liftM ((,) x) ys
and return [(Int,Int)]
, where the first number in each pair is always x
and the second is one of ys
. (Note that for lists liftM
is the same as map
.) And the second function will read the value of x
from its input:
test1 = let m = [1,2]
ys = [4, 5, 6]
in m >>= (\x -> liftM ((,) x) ys >>= (\(x', y) -> return (x', y)))
(The monadic function \(x', y) -> return (x', y)
could be now simplified just to return
, and subsequently >>= return
removed completely, but let's keep it there for the sake of the argument.)
Now each monadic function is self-contained and we can apply the associativity law:
test2 = let m = [1,2]
ys = [4, 5, 6]
in (m >>= \x -> liftM ((,) x) ys) >>= (\(x, y) -> return (x, y))