1. The Easy Part
  2. Higher Order Functions
  3. Types
  4. Lists
  5. Complex Data Objects
  6. File IO
  7. Classes
  8. Monads
  9. List Monads
  10. Shared Transactional Memory

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.

listm.hs
1main = putStrLn(show(do
2    x <- [1..9]
3    return (2*x)))
$ ghc --make listm.hs
[1 of 1] Compiling Main             ( listm.hs, listm.o )
Linking listm ...
$ ./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.

listm2.hs
1import Monad
2 
3main = putStrLn(show(do
4    x <- [1..9]
5    guard(x `mod` 3 /= 0)
6    return (2*x)))
$ ghc --make listm2.hs
[1 of 1] Compiling Main             ( listm2.hs, listm2.o )
Linking listm2 ...
$ ./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.

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

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

listm4.hs
1import Monad
2 
3main = putStrLn(show(do
4    x <- [1..9]
5    case (x `mod` 3 /= 0) of
6        True -> [2*x]
7        False -> []
8        ))
$ ghc --make listm4.hs
[1 of 1] Compiling Main             ( listm4.hs, listm4.o )
Linking listm4 ...
$ ./listm4
[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.

q8.hs
1import Monad
2 
3nocapture p1 [] = True
4nocapture (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 
10boards = 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 
28main = putStrLn(show(take 8 boards))
$ ghc --make q8.hs
[1 of 1] Compiling Main             ( q8.hs, q8.o )
Linking q8 ...
$ ./q8
[(1,1),(2,5),(3,8),(4,6),(5,3),(6,7),(7,2),(8,4)]