All Articles

Introduction to Monads

Monad is a typeclass which allows its instances to be chained using a set of operators. All Monads must implement a group of functions that are collectively known as the Monad Laws. In Haskell, two of these functions are implemented as infix operators, and the remaining third as a regular function. This is roughly how Haskell defines them:

class (Monad m) where
  (>>=) :: Monad m => m a -> (a -> m b) -> m b
  (>>) :: Monad m => m a -> m b -> m b
  return :: Monad m => a -> m a

Bind

The first operator (>>=) is called “bind”. It takes two arguments:

  1. A datatype that conforms to the Monad typeclass, and has a type of ‘a’
  2. A function that takes an ‘a’ as an argument, returns a Monad of type ‘b’
-- IO is a built-in Monad
-- getLine :: IO String
-- putStrLn :: String -> IO ()

duckName :: IO ()
duckName =
    getLine >>= \line ->
    putStrLn ("Quack " ++ line)

In this example, IO receives a line, then passes it as a string to a function, manipulates it, and finally puts it inside another IO Monad.

Generally speaking, the >>= performs the given monadic operation, and binds the resulting value into the given function. Which then returns a new Monad which was computed using that value.

Then

The second operator (>>) is called “then”. It also takes two arguments:

  1. A datatype that conforms to the Monad typeclass, and has a type of ‘a’.
  2. A datatype that conforms to the Monad typeclass, and has a type of ‘b’.
-- putStrLn :: String -> IO ()
-- putStr :: String -> IO ()
helloWorld :: IO ()
helloWorld =
    putStr "Hello " >>
    putStrLn "world"

In this example, IO receives a line, then another line, and finally displays both lines.

Intuitively, the >> takes two monadic operations, and sequentially invokes them. The second operation takes the context of the first to continue its evaluation. In this example, the context is () since putStrLn returns IO ().

Return

The third function is return. It takes one argument, any value type

Note that return in Monads is not the same as the return statement found in object-oriented programming languages.

monad1 :: (Monad m, Num a) => m a
monad1 = return 1

In this example, return takes an Integer and places it inside a Monad.

In general terms, the return function takes a value of type a and places it inside a Monad container.

Summary

Using the Monad Laws, Monads can perform sequential operations without relying on imperative programming. For example, the previous examples can be chained into a single operation:

helloDuckName =
    getLine >>= \line ->
    putStrLn ("Quack " ++ line) >>
    putStrLn ("Hello, " ++ line) >>
    return 1
Sources
Published 3 Dec 2015