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 |
1 | main = 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 |
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
[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 |
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 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 |
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 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 |
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
[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)]
|
|