Haskell "do" notation is a way of writing code to sequence some actions. However, it's simply just syntactic sugar for two functions,
>>=
and >>
that have the following types:
*Main> :t (>>=)
(>>=) :: (Monad m) => m a -> (a -> m b) -> m b
*Main> :t (>>)
(>>) :: (Monad m) => m a -> m b -> m b
>>
performs the first action, discarding the result, and then the second. The result of the function is the value of the second action.
*Main System.Environment> getEnv "HOME"
"/home/jfoster"
*Main System.Environment> getEnv "USER"
"jfoster"
*Main System.Environment> getEnv "HOME" >> getEnv "USER"
"jfoster"
The result of chaining together the getEnv (
String :: IO(String)
) calls is to ignore the return value of the first action.>>=
takes the output of the first action, and feeds it into the second.
*Main System.Directory> canonicalizePath "foo"
"/home/haskell/foo"
*Main System.Directory> makeRelativeToCurrentDirectory "/home/haskell/foo"
"foo"
*Main System.Directory> canonicalizePath "foo" >>= makeRelativeToCurrentDirectory
"foo"
As well as sequencing actions using
>>
and >>=
there are a whole family of functions to do with evaluating actions.mapM :: (Monad m) => (a -> m b) -> [a] -> m [b]
takes a list of actions and performs the action specified for each one (when evaluated, remember it's lazy!), collecting together the results.
*Main System.Environment> mapM getEnv ["HOME","USER"]
["/home/jfoster","jfoster"]
mapM_ :: (Monad m) => (a -> m b) -> [a] -> m ()
does exactly the same as mapM EXCEPT it discards the results. Useful for ensuring the side effects happen (for example, IO). Function names that end with a "M" are usually related to monads, and function names that end with an "_" typically discard their results.Back to do blocks. Typically the final construct in a do block is a return statement. As I said previously
return
is like the opposite of <- - it takes a pure value and constructs an action out of it. Now that I understand a bit more Haskell the type definition of return makes more sense.
return :: (Monad m) => a -> m a
There's some more information about do notation on the Haskell wiki.