Haskell Monads
Let us talk about the most popular typeclass in Haskell, i.e. monads.
The main usage of monads in Haskell is to make effects wrap inside a context, so that it has a type. Thus Haskell is a pure language not because it does not have side-effects but because every effect is typed in Haskell.
class Monad m where
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
x >> y = x >>= \_ -> yfail :: String -> m a
fail msg = error msg
Monad class in Haskell has four functions. return converts an element of type a to a monad (recall pure in Applicatives). (>>=) function(read as “bind”) takes a monadic term, and a function (that takes a non monadic term and returns a monadic term), and returns a monadic term. (>>) and fail functions come with their default implementations. That’s why while creating monad instances it is not mandatory to implement (>>) and fail function.
An instance of Maybe monad can be like the following.
instance Monad Maybe where
return x = Just x
Nothing >>= f = Nothing
Just x >>= f = f x
fail _ = Nothing
Maybe is functor, applicative and a monad as its an instance of all these three typeclasses.
One can create their own monads. It is not absolutely necessary to be an instance Monad typeclass for it to be a monad. In fact anything that obeys the monad laws is a monad. These laws are as follows.
a) Left Identity — applying return to a value x, then applying the resulting value to (>>=) with a function f will give us the result same as f x, i.e.
return x >>= f is same as f x
b) Right Identity — this law is very simple. Say we have a monadic term (M a), and bind is of type M a → (a → M b) → M b . Then if we apply bind with M a and return (whisch is of type a → M a) then the result is M a, i.e. the result is same as the first input parameter. To put it in one sentence
M>>= return is same as M
c) Associativity — bind function is associative.
(m >>= f) >>= g is same as m >>= (\x -> f x >>= g)
The following discussion is inspired from the paper The essence of functional programming by Philip Wadler. The following monads are not instances of Haskell Monad typeclass. Each of them implements three functions: unit, bind and show. They are monads because they follow the three monad laws.
- Identity Monad —
type I a = aunitI a = a
a ‘bindI‘ k = k a
showI a = showval a
2. Monad to add error messages to the interpreter of fig 1. in the paper.
data E a = Success a | Error StringunitE a = Success a
errorE s = Error s
(Success a) ‘bindE‘ k = k a
(Error s) ‘bindE‘ k = Error s
showE (Success a) = “Success: “ ++ showval a
showE (Error s) = “Error: “ ++ s