| 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)]
|
| |