In functional programming, a monad is a kind of abstract data type used to represent computations (instead of data in the domain model). Programs written in functional style can make use of monads to structure procedures that include sequenced operations, or to define arbitrary deterministic control flows (like handling concurrency, continuations, or exceptions).
Formally, a monad is constructed by defining two operations bind and return and a type constructor M that must fulfill several properties. These properties make possible the correct composition of functions that use values from the monad as their arguments (so called monadic functions). The monad acts as a framework in that it's a reusable behavior that decides the order in which the specific monadic functions are called, and manages all the undercover work required by the computation.
The primary uses of monads in functional programming are to express input/output (I/O) operations and changes in state without using language features that introduce side effects. Although a function cannot directly cause a side effect, it can construct a value describing a desired side effect that the caller should apply at a convenient time. However, I/O and state management are by no means the only uses of monads. They are useful in any situation where the programmer wants to carry out a purely functional computation while a related computation is carried out "on the side." In imperative programming the side effects are embedded in the semantics of the programming language; with monads, they are made explicit in the monad definition.
The name monad derives from category theory, a branch of mathematics that describes patterns applicable to many mathematical fields. (As a minor terminological mismatch, the term "monad" in functional programming contexts is usually used with a meaning corresponding to that of the term "strong monad" in category theory, a specific kind of category theoretical monad.)
The Haskell programming language is a functional language that makes heavy use of monads, and includes syntactic sugar to make monadic composition more convenient. All of the code samples below are written in Haskell unless noted otherwise.
-- par is a function that takes two real numbers and returns another
par :: Float -> Float -> Float
par x y = 1 / ((1 / x) + (1 / y))
Instead of avoiding any errors by checking whether each divisor is zero, it might be convenient to have a modified division operator that does the check implicitly, as in the following pseudocode:
-- // is an operator that takes two "Maybe Float"s and returns another.
-- "Maybe Float" extends the Float type to represent calculations that may fail.
(//) :: Maybe Float -> Maybe Float -> Maybe Float
x // y = ... -- the definition appears below.
par :: Float -> Float -> Maybe Float
par x y = 1' // ((1' // x') +' (1' // y')) -- where 1', x', y' are the "Maybe" versions of 1, x, y and +' "adds" Maybe Floats.
-- See below for details.
With the // operator, dividing by zero anywhere in the computation will result in the entire computation returning a special value of the Maybe monad called "Nothing", which indicates a failure to compute a value. Otherwise, the computation will produce a numerical result, contained in the other Maybe value, which is called "Just". The result of this division operator can then be passed to other functions. This concept of "maybe values" is one situation where monads are useful.
The usual formulation of a monad for programming is known as a Kleisli triple, and has the following components:
In Object-oriented programming terms, the type construction would correspond to the declaration of the monadic type, the unit function takes the role of a constructor method, and the binding operation contains the logic necessary to execute its registered callbacks (the monadic functions).
In practical terms, a monad, unlike your everyday function result, stores function results and side-effect representations. This allows side effects to be propagated through the return values of functions without breaking the pure functional model. For example, Haskell's Maybe monad can have either a normal return value, or Nothing. Similarly, error monads (such as Either e, for some type e representing error information) can have a normal return value or an error value.
data Maybe t = Just t | NothingThe Maybe value corresponding to an underlying value, is just that value (represented by wrapping with "Just").
return x = Just xBinding a function to something that is just a value means applying it directly to that value (the function must return a monadic type). Binding a function to nothing produces nothing.
mBind :: Maybe a -> (a -> Maybe b) -> Maybe b
(Just x) `mBind` f = f x
Nothing `mBind` f = Nothing
Just a and Just b, from which a and b are extracted. If b is zero, (/) cannot be applied, so "Nothing" is returned, otherwise "Just (a / b)" is returned:(//) :: Maybe a -> Maybe a -> Maybe a
_ // Nothing = Nothing
Nothing // _ = Nothing
_ // Just 0 = Nothing
Just x // Just y = Just (x / y)
This is the definition of the same Maybe monad in the F# language:
let bind d f =
type MaybeBuilder() =
let maybe = MaybeBuilder() match d with
| None -> None
| Some(v) -> f v
let result v = Some(v)
let delay f = f() member x.Bind(v, d) = bind v d
member x.Return(v) = result v
member x.Delay(f) = delay f
member x.Let(v, f) = bind (result v) f
(return x) >>= f ≡ f x
m >>= return ≡ m
(m >>= f) >>= g ≡ m >>= (x -> f x >>= g)
In the last rule, the notation x -> defines an anonymous function that maps any value x to the expression that follows.
mzero >>= f ≡ mzero
Similarly, binding any m with a function that always returns a zero results in a zero
m >>= (x -> mzero) ≡ mzero
Intuitively, the zero represents a value in the monad that has only monad-related structure and no values from the underlying type. In the Maybe monad, "Nothing" is a zero. In the List monad, "[]" (the empty list) is a zero.
>>= directly in a program, it is more typical to use a format called do-notation (perform-notation in OCaml, computation expressions in F#), that mimics the appearance of imperative languages. The compiler translates do-notation to expressions involving >>=. For example, the following definitions both give the value [(3,42),(3,42),(4,42),(4,42)] to a:a = do x <- [3..4]
[1..2]
return (x, 42)
a = [3..4] >>= (x -> [1..2] >>= (_ -> return (x, 42)))
Notice that the list [1..2] is not used. The lack of a left-pointing arrow, translated into a binding to a function that ignores its argument, indicates that only the monadic structure is of interest, not the values inside it; for the list monad this is trivial, but e.g. for a state monad this might be used for changing the state without producing any more result values. The do-block notation can be used with any monad as it is simply syntactic sugar for >>=.
The following definitions for safe division for values in the Maybe monad are also equivalent:
x // y = do
a <- x -- Extract the values "inside" x and y, if there are any.
b <- y
if b == 0 then Nothing else Just (a / b)
x // y = x >>= (a -> y >>= (b -> if b == 0 then Nothing else Just (a / b)))
A similar example in F# using a computation expression:
let secure_div =
let s = Console.ReadLine()
let succ,v = Int32.TryParse(s)
if (succ) then Some(v) else None
maybe { let! x = readNum()
let! y = readNum()
if (y = 0)
then None
else return (x / y)
}
The syntactic sugar of the maybe block would get translated internally to the following expression:
maybe.Bind(readNum(), fun x ->
maybe.Bind(readNum(), fun y ->
if (y=0) then None else maybe.Return(x/y ))))
liftM2 :: Monad m => (a -> b -> c) -> m a -> m b -> m c
liftM2 op mx my = do
x <- mx
y <- my
return (op x y)
Recall that arrows in a type associate to the right, so liftM2 is a function that takes a binary function as an argument and returns another binary function. The type signature says: If m is a monad, we can "lift" any binary function into it. For example:
(.*.) :: Monad m => Maybe Float -> Maybe Float -> Maybe Float
x .*. y = liftM2 (*) x y
defines an operator (.*.) which multiplies two numbers, unless one of them is Nothing (in which case it again returns Nothing). The advantage here is that we need not dive into the details of the implementation of the monad; if we need to do the same kind of thing with another function, or in another monad, using liftM2 makes it immediately clear what is meant (see Code reuse).
add x y = do
x' <- x
y' <- y
return (x' + y')
par x y = let
one = return 1
jx = return x
jy = return y
in one // (add (one // jx) (one // jy))
If the result of any division is Nothing, it will propagate through the rest of the expression.
Id t = t
return x = x
x >>= f = f x
A do-block in this monad performs variable substitution; do {x <- 2; return 3*x} results in 6.
-- "return" constructs a one-item list.
return x = [x]
-- "bind" concatenates the lists obtained by applying f to each item in list xs.
xs >>= f = concat (map f xs)
-- The zero object is an empty list.
mzero = []
In the list monad, a do-block is a list comprehension. For example, do {x <- [1..n]; return (2*x)} corresponds to the mathematical expression "(2×1,2×2,...,2×n)."
The monads for sets and multisets support the use of set-builder notation similarly. The set monad is useful when the state of a computation is ambiguous, as in a parser that has not read enough input to decide what syntax it is reading. The parser can maintain a set that represents the possible syntaxes, and scan until the set has one item (meaning that a syntax was recognized) or no items (meaning that the input is unacceptable).
do
putStrLn "What is your name?"
name <- getLine
putStrLn ("Nice to meet you, " ++ name ++ "!")
type StateTrans s t = s -> (t, s)
Note that this monad, unlike those already seen, takes a type parameter, the type of the state information. The monad operations are defined as follows:
-- "return" produces the given value without changing the state.
return x = s -> (x, s)
-- "bind" modifies transformer m so that it applies f to its result.
m >>= f = r -> let (x, s) = m r in (f x) s
Useful state transformers include:
readState = s -> (s, s) -- Examine the state at this point in the computation.
writeState x = s -> ((), x) -- Replace the state.
Another operation applies a state transformer to a given initial state:
applyTrans:: StateTrans s a -> s -> (a, s)
applyTrans t s = t s
do-blocks in a state monad are sequences of operations that can examine and update the state data.
The two formulations are related as follows. As before, the ≡ symbol indicates equivalence between two Haskell expressions.
(map f) m ≡ m >>= (x -> return (f x))
join m ≡ m >>= (x -> x)
m >>= f ≡ join ((map f) m)
In addition to IO, scientific articles and Haskell libraries have successfully applied monads to topics including parsers and programming language interpreters. The concept of monads along with the Haskell do-notation for them has also been generalized to form arrows.
Haskell and its derivatives have been for a long time the only major users of monads in programming. There exist formulations also in Scheme and Perl, and monads have been an option in the design of a new ML standard. Recently the research language F# has included a feature called computation expressions or workflows, which are an attempt to introduce monadic constructs within a syntax more palatable to programmers with an imperative background.
There exists a tutorial for monads in Scala (http://lamp.epfl.ch/~emir/bqbase/2005/01/20/monad.html) with examples of comprehensions and continuations.
Effect systems are an alternative way of describing side effects as types.