Monad is a special class which looks like this:

 mon.hs 1 -- basic Monad instance! yeah! 2 data Moo a = Cow a deriving(Eq,Ord,Show) 3 4 --uncow :: Moo Float -> Float 5 uncow (Cow a) = a 6 7 instance Monad Moo where 8 return m = Cow m 9 f >>= k = k (uncow f) 10 11 plustwo x = Cow (x+2) 12 minusone x = Cow (x-1) 13 square x = Cow (x*x) 14 15 main = putStrLn(show(Cow 3 >>= plustwo >>= minusone >>= square)) ```\$ ghc --make mon.hs [1 of 1] Compiling Main             ( mon.hs, mon.o ) Linking mon ... ``` ```\$ ./mon Cow 16 ```

Basically, the >>= is a special operator which takes a data type (in this case "Moo a"), obtains the value supplied to its constructor (in this case "a") and a function (we have three examples here, plustwo, minusone, square) and constructs a new type based on that value.

It turns out that this is the magic that makes "do" work.

 mon2.hs 1 data Moo a = Cow a deriving(Eq,Ord,Show) 2 3 --uncow :: Moo Float -> Float 4 uncow (Cow a) = a 5 6 instance Monad Moo where 7 return m = Cow m 8 f >>= k = k (uncow f) 9 10 plustwo x = Cow (x+2) 11 minusone x = Cow (x-1) 12 square x = Cow (x*x) 13 14 main = putStrLn(show(do 15 x <- Cow 3 16 x2 <- plustwo x 17 x3 <- minusone x2 18 x4 <- square x3 19 return x4)) ```\$ ghc --make mon2.hs [1 of 1] Compiling Main             ( mon2.hs, mon2.o ) Linking mon2 ... ``` ```\$ ./mon2 Cow 16 ```

The <- keyword is a special thing that extracts the constructor from our base type. Each function we apply creates a new type of "Moo."

Now let's see that done with IO:

 mon3.hs 1 main = (putStrLn "line 1") >>= 2 \x -> (putStrLn "line 2") >>= 3 \x -> (putStrLn "line 3") ```\$ ghc --make mon3.hs [1 of 1] Compiling Main             ( mon3.hs, mon3.o ) Linking mon3 ... ``` ```\$ ./mon3 line 1 line 2 line 3 ```

Here's another variant of the same program:

 mon4.hs 1 main = do 2 x <- (putStrLn "line 1") 3 x2 <- (putStrLn "line 2") 4 x3 <- (putStrLn "line 3") 5 return x3 ```\$ ghc --make mon4.hs [1 of 1] Compiling Main             ( mon4.hs, mon4.o ) Linking mon4 ... ``` ```\$ ./mon4 line 1 line 2 line 3 ```

The sequence of statements in a "do" block translate to a sequence of applications of the >>= function. This, essentially, creates the artificial data dependency that the compiler needs in order to apply our putStrLn calls in sequence.

The Monad has other uses than IO, however. Here we create a sort of exception system.

 divz.hs 1 data DValt a = DVal a | Fail String 2 deriving(Eq, Ord, Show) 3 4 instance Monad DValt where 5 return a = DVal a 6 (DVal k) >>= f = f k 7 (Fail s) >>= f = Fail s 8 9 invert x = 10 if x == 0.0 then 11 Fail "Div by zero" 12 else 13 DVal (1.0/x) 14 15 main = putStrLn(show( 16 (DVal 3.4) >>= 17 \x -> (DVal (x-3.4)) >>= 18 invert >>= 19 \x -> (DVal (x*x)) 20 )) ```\$ ghc --make divz.hs [1 of 1] Compiling Main             ( divz.hs, divz.o ) Linking divz ... ``` ```\$ ./divz Fail "Div by zero" ```

Once a "Fail" shows up in the sequence of operations, that is all that can show up.

 prev next