List Monads

You can use a list as a Monad. The primary difference between list as monads and other sorts of monads is the behavior of the <- keyword.

file: listm.hs
1 main = putStrLn(show(do
2     x <- [1..9]
3     return (2*x)))
> ghc --make listm.hs; ./listm
[1 of 1] Compiling Main             ( listm.hs, listm.o )
Linking listm ...
[2,4,6,8,10,12,14,16,18]

One of the really interesting tricks you can do with the list monad involves the guard() statement.

file: listm2.hs
1 import Monad
2 
3 main = putStrLn(show(do
4     x <- [1..9]
5     guard(x `mod` 3 /= 0)
6     return (2*x)))
> ghc --make listm2.hs; ./listm2
[1 of 1] Compiling Main             ( listm2.hs, listm2.o )
Linking listm2 ...
[2,4,8,10,14,16]

The guard blocks processing of the items in the list if the condition inside it is met. You can get the same effect using case.

file: listm2.hs
1 import Monad
2 
3 main = putStrLn(show(do
4     x <- [1..9]
5     case (x `mod` 3 /= 0) of
6         True -> return (2*x)
7         False -> []
8         ))
> ghc --make listm2.hs; ./listm2
[2,4,8,10,14,16]

Note that "return x" is the same as "[x]" in the context of a list monad.

file: listm3.hs
1 import Monad
2 
3 main = putStrLn(show(do
4     x <- [1..9]
5     case (x `mod` 3 /= 0) of
6         True -> [2*x]
7         False -> []
8         ))
> ghc --make listm3.hs; ./listm3
[1 of 1] Compiling Main             ( listm3.hs, listm3.o )
Linking listm3 ...
[2,4,8,10,14,16]

For your viewing pleasure, here's a version of the Eight Queens problem implemented using the list monad. Possibly not the most elegant solution -- but you can see that using guards in this case causes much less pain than eight "case ... of" structures.

file: q8.hs
1 import Monad
2 
3 nocapture p1 [] = True
4 nocapture (x1,y1) ((x2,y2):rest) =
5     if (x1==x2) || (y1==y2) || (x1-x2==y1-y2) || (x1-x2==y2-y1) then
6         False
7     else
8         nocapture (x1,y1) rest
9 
10 boards = do
11     q1 <- [(1,i) | i <- [1..8]]
12     q2 <- [(2,i) | i <- [1..8]]
13     guard(nocapture q1 [q2])
14     q3 <- [(3,i) | i <- [1..8]]
15     guard(nocapture q3 [q2,q1])
16     q4 <- [(4,i) | i <- [1..8]]
17     guard(nocapture q4 [q3,q2,q1])
18     q5 <- [(5,i) | i <- [1..8]]
19     guard(nocapture q5 [q4,q3,q2,q1])
20     q6 <- [(6,i) | i <- [1..8]]
21     guard(nocapture q6 [q5,q4,q3,q2,q1])
22     q7 <- [(7,i) | i <- [1..8]]
23     guard(nocapture q7 [q6,q5,q4,q3,q2,q1])
24     q8 <- [(8,i) | i <- [1..8]]
25     guard(nocapture q8 [q7,q6,q5,q4,q3,q2,q1])
26     [q1,q2,q3,q4,q5,q6,q7,q8]
27 
28 main = putStrLn(show(take 8 boards))
> ghc --make q8.hs; ./q8
[1 of 1] Compiling Main             ( q8.hs, q8.o )
Linking q8 ...
[(1,1),(2,5),(3,8),(4,6),(5,3),(6,7),(7,2),(8,4)]