Monad (functional programming)

In functional programming, a monad is a design pattern [1] that allows structuring even complex program logic in a way that is both generic and declarative. More specifically, a monad generically transforms underlying data types into richer types with a couple of abstract operations, which in turn must follow a few formal rules known as the monad laws.[2] So long as these criteria are met, monads can represent many kinds of computations at a high level of abstraction, not just pure functions.[3]

This allows monads to simplify a wide range of problems elegantly, keeping the many benefits of purely functional programming like referential transparency, but without any need to extend the language's main semantics. One common use-case among many others is chaining functions in a logical sequence (though not necessarily in time); with monads, a programmer can build a succinct pipeline of functions that also isolates side-effects.[4][5]

Some languages, particularly functional ones like Haskell, offer libraries with definitions for a general monad and often-used instances.[6] However, since monads are ultimately an abstract concept, one can implement them conveniently in any language that supports parametric polymorphism.

Overview

The idea of a monad originally comes from category theory, though due to the fact that functions on multiple free variables are common in programming, "monads" as described in this article are technically what category theorists would call "strong monads".[3]

When translated into functional programming terms, a monad acts as a type class (or an equivalent language feature), a transformation that applies to underlying types generically instead of relying on the semantics of individual types. This ability to work on a type while remaining agnostic about its operational details gives monads much of their expressive power. What sets monads apart from other type classes though are their standard operations.[7]

The monad pattern does not arise as often in object-oriented programming, but many object-oriented languages offer a mechanism roughly equivalent to type classes, generics in Java or templates in C++ for instance. One can use these features to implement and deploy monads even in languages that are not normally considered functional.

Conceptual Definition

Altogether, a monad contains three parts (an alternate definition is given later under § fmap and join):

  1. A type constructor that specifies how the monadic type is built up from other pre-existing types.[lower-alpha 1]
  2. A unary operator, often called "return" or "unit", which wraps an underlying variable in the monad.[lower-alpha 2]
  3. A combinator, typically called "bind" (as in binding a variable), that unwraps a monadic variable, inserts it into a function (without necessarily evaluating it), then rewraps the result in the monad.[lower-alpha 3]

To fully qualify as a monad, these three parts must also respect a few laws, which the programmer must check or prove independently.[2] These laws intuitively come down to...

  1. Using unit on a variable only to immediately bind it to a function should be redundant and no different from just applying the function to the original variable.
  2. Using bind to feed an already monadic variable to unit is also redundant and should have no effect.
  3. In a chain of sequential binds, the order in which the bind operator is evaluated should be irrelevant.[lower-alpha 4]

A more precise explanation of the monad operations and laws can be found below, under § Formal definition. The upshot is that when all of these criteria are satisfied, monads can reify computational steps and structure a program very concisely, even with side-effects, while keeping the rigor and flexibility of purely functional programming.[5][8]

Utility

The monad pattern has proven valuable for combining abstract usability with functional precision in many diverse scenarios, not limited to:

A very common use for monads, one that speaks directly to the functional programming approach, is using a chain of binds to feed a monad through a sequence of functions. Because of this, monads have been described as "programmable semicolons", a reference to the use of semicolons in many imperative programming languages to mark sequential statements.[2] It should be stressed, however, that ordering program flow is only one of many applications for monads; some monads can pass along extra information through bind that is inaccessible within the function, and some even exert finer control over execution flow, for example only calling a function under certain conditions. Their general utility lies in simplifying a program's structure and improving separation of concerns through abstraction.[5][9]

In purely functional programming, computations cannot rely on any sort of state without complex workarounds, nor should order of evaluation matter. Only the order of function composition, whether through currying or some other formalism, should influence the final result. However, this disciplined approach to programming can sometimes lead to very complex program logic even when impure computations are not an issue.[4]

Functional languages can handle all of these situations by expressing program logic in continuation-passing style (CPS), which is granular and transparent yet extremely dense. With a well-designed monad though, rather than managing this scaffolding explicitly, a programmer can abstract it all away and simply order functions within a pipeline. Essentially, each specific pattern that appears in CPS logic can be encapsulated by a distinct monad.[5] Since an application programmer can implement domain logic while offloading bookkeeping onto pre-developed monads, they can even be considered a sort of aspect-oriented programming.[10]

An example: Maybe (pseudocode)

A very common issue in strict programs is preparing for undefined operations or variables. This turns out to be a very natural application for a monad, specifically one known as the Maybe monad.

First, assume a high-level, functional language with the following features:

  • An undefined value Nothing
  • An equational syntax for definitions
  • Generic types and support for type inference
  • First-order functions, with the symbol -> as shorthand for a function from inputs to outputs
  • Purely for simplicity's sake, binding variables is automatic (e.g. mx binds x when passed to a function)

Within this language, we can specify a new option type, called Maybe, that can contain either a single value of any type or no value at all. To avoid any chance of confusion, we also use a term Just to distinguish a plain value from one embedded in our new type:

newtype (Maybe T)    =    (Just T or Nothing)

We would like to use this type as a simple sort of checked exception: if the computation becomes undefined at any point, it will short-circuit and return Nothing. If all steps of the calculation succeed though, the final result should just be the correct value.

Now imagine a simple addition function add that does exactly this when adding two variables mx and my. If we naively attempt to write functions with this kind of behavior, we'll end up with a nested series of "if Nothing then Nothing else..." statements.[2] In pseudocode, a type signature and definition might look a bit like this:

add : (Maybe Integer, Maybe Integer) -> Maybe Integer

add (mx, my) =
    if mx is Nothing
        Nothing
    else
        if my is Nothing
            Nothing
        else
            Just (x + y)

To alleviate this, we can define an operation for chaining the steps together; we'll use the infix symbol >>= and define it to feed a (possibly undefined) result from each step into the next. Since we are technically inserting the result into another function, we will take a function as input to our operator. The add function already fixes down the underlying types for us too so we may as well allow this operator to output a different type from the input:

>>= : (Maybe T, (T -> Maybe U)) -> Maybe U

(ma >>= f) =
    if ma is (Just a)
        f(a)             -- If input is defined, apply function f to it
    else
        Nothing          -- If input is undefined, so is the output

We can now rewrite add in our language as something much more compact:

add (mx, my)    =    mx >>= (my >>= Just (x + y))

This is more elegant, but a little extra analysis reveals something far more powerful. For one, notice that within either version of add, Just is only needed to tag a plain value as now a Maybe value. To emphasize how Just acts on a value, we can wrap it in its own function, which we'll call eta for now:

eta : T -> Maybe T

eta x    =    Just x     -- Ensure a plain value is elevated to a Maybe value

The key insight is that now we have two functions, >>= and eta, which greatly simplify our add function without any specific dependence on add whatsoever. We can, in fact, apply these functions to simplify any code that works on the Maybe type, even if the underlying types are entirely different; for example, here is a concise NOT operator from (Kleene's) trinary logic that completely automates undefined values:

trinot: Maybe Boolean -> Maybe Boolean

trinot mp    =    mp >>= (eta (not p))

The Maybe type along with the two generic functions is a monad, >>= acting as bind and eta as unit. We can check that these operations respect the monad laws too (explained in more detail below).

Other monads will embody different logical processes, and the extra features described later can make some monads even more powerful, but all of those variations are grounded in the basic principles laid out here.

History

The term "monad" in programming actually goes all the way back to the APL and J programming languages, which do tend toward being purely functional. However, in those languages, "monad" was simply shorthand for a function taking one parameter (a function with two parameters being a "dyad", and so on). This usage predates the first discussions of programming with true monads by decades and is roughly contemporaneous with the first work on monads in category theory.

The mathematician Roger Godement was the first to formulate the concept of a monad in the late 1950s. Over the next decades, as theorists developed the idea further, the term "monad" due to mathematician and leading category-theorist Saunders Mac Lane came to dominate.

Starting in the 1980s, a vague notion of monadic programming, or its equivalent, began to surface in the computer science community. The research language Opal included a "command" feature that worked similarly to a monad. However, the feature was more ad-hoc and never formally specified or linked to a deeper underlying theory. According to programming language researcher Philip Wadler, computer scientist John C. Reynolds anticipated several facets of the monad pattern in the 70s and early 80s; Reynolds had discussed the value of continuation-passing style (which is intimately connected), category theory as a rich source for program semantics, and the type distinction between values and computations on them.[5]

The computer scientist Eugenio Moggi was the first to make an explicit link between the monad of category theory and functional programming, in a conference paper in 1989,[11] followed by a more refined journal submission in 1991. In earlier work, several computer scientists had advanced the idea of using category theory to provide general semantics for the lambda calculus. Moggi's key insight from here was that a real program is not just a function that maps values to other values, but rather a transformation that takes values and converts them to computations on those values. When formalized in category-theoretic terms, this leads to the conclusion that a monad is the structure that can represent these computations.[3]

Several others popularized and built on this idea, including Philip Wadler[4] and Simon Peyton Jones, both of whom were involved in the specification of Haskell. In particular, early versions of Haskell used a problematic "lazy list" model for I/O, and Haskell 1.3 introduced a monadic interface as a more flexible way to combine I/O with lazy evaluation. Besides I/O, programming language researchers and library designers successfully applied monads in Haskell to a wide range of design problems; the Haskell community also pioneered the use of § Imperative Syntax Sugar (known in Haskell as "do-notation") and extended monadic programming into a wider hierarchy of structures including applicative functors and arrows.

For a long time, programming with monads was largely confined to Haskell and its derivatives, but as functional programming influenced other paradigms, many languages have incorporated the monad pattern (if not the name) into their features and libraries. Formulations now exist in Scheme, Perl, Python, Racket, Clojure, Scala, F#, and have also been considered for a new ML standard.

Formal definition

The complex multivalued square and cube root functions may be composed so they produce the sixth root function. The structure that governs the type of input and output and the structure that composes the different operations are, together, a list monad.[12]
The bullet symbol • denotes the bind operator, z is a complex number, and the square brackets denote an array:
unit(z) := [ z ]
(fg)(z) := append(map(f,g(z)))
lift(f) =  := unitf = funit
sqrt°(z) =
= append(map(unit,sqrt(z)))
= append(map(sqrt,unit(z)))
sxrt(z) = (cbrt°sqrt°)(z) =
= append(map(cbrt°,sqrt°(z)))

A monad is a construction that, given an underlying type system, embeds a corresponding type system (called the monadic type system) into it (that is, each monadic type acts as the underlying type). This monadic type system preserves all significant aspects of the underlying type system, while adding features particular to the monad.[lower-alpha 5]

The usual formulation of a monad for programming is known as a Kleisli triple, and has the following components:

  1. A type constructor that defines, for every underlying type, how to obtain a corresponding monadic type. In Haskell's notation, the name of the monad represents the type constructor. If M is the name of the monad and t is a data type, then M t is the corresponding type in the monad.
  2. A unit function that injects a value in an underlying type to a value in the corresponding monadic type. The unit function has the polymorphic type t→M t. The result is normally the "simplest" value in the corresponding type that completely preserves the original value (simplicity being understood appropriately to the monad). In Haskell, this function is called return due to the way it is used in the do-notation described later.
  3. A binding operation of polymorphic type (M t)→(t→M u)→(M u), which Haskell represents by the infix operator >>=. Its first argument is a value in a monadic type, its second argument is a function that maps from the underlying type of the first argument to another monadic type, and its result is in that other monadic type. Typically, the binding operation can be understood as having four stages:
    1. The monad-related structure on the first argument is "pierced" to expose any number of values in the underlying type t.
    2. The given function is applied to all of those values to obtain values of type (M u).
    3. The monad-related structure on those values is also pierced, exposing values of type u.
    4. Finally, the monad-related structure is reassembled over all of the results, giving a single value of type (M u).

Given a type constructor M, in most contexts, a value of type M a can be thought of as an operation that returns a value of type a. The return operation takes a value from a plain type a and puts it into a monadic container of type M a; the bind operation chains a monadic value of type M a with a function of type a  M b to create a monadic value of type M b.

Monad laws

For a monad to behave correctly, the definitions must obey a few axioms, together called the monad laws.[13] The ≡ symbol indicates equivalence between two Haskell expressions in the following text.

  • return acts approximately as a neutral element of >>=, in that:
    • (return v) >>= f f v
    • m >>= return m
  • Binding with two functions in succession is the same as binding with their monadic-style composition:
    • (m >>= f) >>= g m >>= ( \x -> (f x >>= g) )

The axioms can also be expressed using expressions in do-block style:

  • do { x <- return v; f x } do { f v }
  • do { x <- m; return x } do { m }
  • do { y <- do { x <- m; f x }; g y } do { x <- m; y <- f x; g y }

or using the monadic composition operator, (f >=> g) x (f x) >>= g :

  • return >=> g g
  • f >=> return f
  • (f >=> g) >=> h f >=> (g >=> h)

fmap and join

Although Haskell defines monads in terms of the return and bind functions, it is also possible to define a monad in terms of return and two other operations, join and fmap. This formulation fits more closely with the original definition of monads in category theory. The fmap operation, with type (tu) → M t→M u,[14] takes a function between two types and produces a function that does the "same thing" to values in the monad. The join operation, with type M (M t)→M t, "flattens" two layers of monadic information into one.

The two formulations are related as follows:

fmap f m = m >>= (return . f)
join n = n >>= id

m >>= g      join (fmap g m)

Here, m has the type M t, n has the type M (M r), f has the type tu, and g has the type t → M v, where t, r, u and v are underlying types.

The fmap function is defined for any functor in the category of types and functions, not just for monads. It is expected to satisfy the functor laws:

fmap id      id
fmap (f . g)      (fmap f) . (fmap g)

The return function characterizes pointed functors in the same category, by accounting for the ability to "lift" values into the functor. It should satisfy the following law:

return . f  fmap f . return

This is equivalent to stating that return is a natural transformation from the identity "id" to "fmap".

In addition, the join function characterizes monads:

join . fmap join      join . join
join . fmap return    join . return = id
join . fmap (fmap f)  fmap f . join

The first two laws correspond to the monad axioms, while the third states that join is a natural transformation from "fmap . fmap" to "fmap".

Additive monads

An additive monad is a monad endowed with a monadic zero mzero and a binary operator mplus satisfying the monoid laws, with the monadic zero as unit. The operator mplus has type M tM tM t (where M is the monad constructor and t is the underlying data type), satisfies the associative law and has the zero as both left and right identity. That is:

(a `mplus` b) `mplus` c      a `mplus` (b `mplus` c)
m `mplus` mzero              m
mzero `mplus` m              m

Thus, an additive monad is also a monoid. For >>=, on the other hand, mzero acts as a null-element. Just as multiplying a number by 0 results in 0, binding mzero with any function produces the zero for the result type:

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.

Syntax sugar

Although there are times when it makes sense to use the bind operator directly in a program, it is very common to use a special format that mimics an imperative language (called do-notation in Haskell, perform-notation in OCaml, computation expressions in F#,[15] and for comprehension in Scala). This is a bit of syntactic sugar where steps are written as a list of statements within a code block; the compiler will then quietly translate these expressions into more functional, monadic code.

do-notation in Haskell

To see how this feature can make code even more elegant, consider the add function from the above § Maybe monad example. That example is actually based on a more precise version in Haskell, where the non-monadic definition of add would be:

add mx my =
    case mx of
        Nothing -> Nothing
        Just x  -> case my of
                       Nothing -> Nothing
                       Just y  -> Just (x + y)

In valid Haskell, return is used for what we called eta in pseudocode, plus lambda expressions must now be handled explicitly. Even with these technicalities, the Maybe monad still makes for a cleaner definition:

add mx my =
    mx >>= (\x ->
        my >>= (\y ->
            return (x + y)))

With do-notation though, we can distill this even further into a very intuitive sequence:

add mx my = do
    x <- mx
    y <- my
    return (x + y)

As another example, the following code:

a = do x <- [3..4]
       [1..2]
       return (x, 42)

is transformed during compilation into:

a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))

It is helpful to see the implementation of the list monad, and to know that concatMap maps a function over a list and concatenates (flattens) the resulting lists:

instance Monad [] where
  m >>= f  = concat (map f m)
  return x = [x]
  fail s   = []

concatMap f = concat . map f

Therefore, the following transformations hold and all the following expressions are equivalent:

a = [3..4] >>= (\x -> [1..2] >>= (\_ -> return (x, 42)))
a = [3..4] >>= (\x -> concatMap (\_ -> return (x, 42)) [1..2] )
a = [3..4] >>= (\x -> [(x,42),(x,42)] )
a = concatMap (\x -> [(x,42),(x,42)] ) [3..4]
a = [(3,42),(3,42),(4,42),(4,42)]

Notice that the values in the list [1..2] are 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, 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 >>=.

Computation expressions in F#

Here is a similar example in F#, which uses computation expressions to define a "safe division" function (returning None if division by 0 occurs):

let readNum () =
  let s = Console.ReadLine()
  let succ,v = Int32.TryParse(s)
  if (succ) then Some(v) else None

let secure_div = 
  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.Delay(fun () ->
  maybe.Bind(readNum(), fun x ->
    maybe.Bind(readNum(), fun y ->
      if (y=0) then None else maybe.Return(x / y))))

Drawbacks

The details of how various languages sugarcoat monads are beyond the scope of this article, but one should always remember that it is purely a syntactic convenience. Imperative-style blocks can always be replaced with direct monadic (or even non-monadic CPS) expressions. While they are convenient in many situations, such as binding several variables (which would otherwise require a great deal of nesting), there are many cases where directly using bind is both clearer and shorter. Some advocates of functional programming even argue that since imperative syntax sugar allows people to carry over poor habits and assumptions from imperative programming, it should be avoided by default and only used when obviously superior.[16][2]

Generic monadic functions

Despite the simplicity a monad pattern brings to a program, one might wonder if this outweighs the inconvenience of redefining new monadic functions. This process would be especially redundant if the monadic functions just mirror ones already defined for plain values. Thankfully, the separation between the semantics of a monad and a monadic function is often complete enough that we can abstract away pretty much the entire function definition. Mathematically speaking, we can "lift" many functions on simple types into functions on monadic types without bothering about details.

In Haskell, for instance, the higher-order function to do this is called liftM2:

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, the add function for Maybe discussed earlier can be condensed in Haskell into the minimal snippet:

add :: Maybe Int -> Maybe Int -> Maybe Int
add = liftM2 (+)

Another example in Haskell shows how we can even lift an operation to work with monads in general, not just one in particular:

(.*.) :: (Monad m, Num a) => m a -> m a -> m a
x .*. y = liftM2 (*) x y

The advantage here is that we need not even dive into which kind of monad we've wrapped our numbers in. Whenever we need a monadic operator, liftM2 can give us one almost immediately so long as it will work analogously to the basic version.

Mathematically, the liftM2 operator is defined by:

Other examples

Identity monad

The simplest monad is the identity monad, which attaches no information to values.

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.

From the category theory point of view, the identity monad is derived from the adjunction between identity functors.

Collections

Some familiar collection types, including lists, sets, and multisets, are monads. The definition for lists is given here.

-- "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 = []

List comprehensions are a special application of the list monad. For example, the list comprehension [ 2*x | x <- [1..n], isOkay x] corresponds to the computation in the list monad do {x <- [1..n]; if isOkay x then return (2*x) else mzero;}.

The notation of list comprehensions is similar to the set-builder notation, but sets can't be made into a monad, since there's a restriction on the type of computation to be comparable for equality, whereas a monad does not put any constraints on the types of computations. Actually, the Set is a restricted monad.[17] The monads for collections naturally represent nondeterministic computation. The list (or other collection) represents all the possible results from different nondeterministic paths of computation at that given time. For example, when one executes x <- [1,2,3,4,5], one is saying that the variable x can non-deterministically take on any of the values of that list. If one were to return x, it would evaluate to a list of the results from each path of computation. Notice that the bind operator above follows this theme by performing f on each of the current possible results, and then it concatenates the result lists together.

Statements like if condition x y then return () else mzero are also often seen; if the condition is true, the non-deterministic choice is being performed from one dummy path of computation, which returns a value we are not assigning to anything; however, if the condition is false, then the mzero = [] monad value non-deterministically chooses from 0 values, effectively terminating that path of computation. Other paths of computations might still succeed. This effectively serves as a "guard" to enforce that only paths of computation that satisfy certain conditions can continue. So collection monads are very useful for solving logic puzzles, Sudoku, and similar problems.

In a language with lazy evaluation, like Haskell, a list is evaluated only to the degree that its elements are requested: for example, if one asks for the first element of a list, only the first element will be computed. With respect to usage of the list monad for non-deterministic computation that means that we can non-deterministically generate a lazy list of all results of the computation and ask for the first of them, and only as much work will be performed as is needed to get that first result. The process roughly corresponds to backtracking: a path of computation is chosen, and then if it fails at some point (if it evaluates mzero), then it backtracks to the last branching point, and follows the next path, and so on. If the second element is then requested, it again does just enough work to get the second solution, and so on. So the list monad is a simple way to implement a backtracking algorithm in a lazy language.

From the category theory point of view, collection monads are derived from adjunctions between a free functor and an underlying functor between the category of sets and a category of monoids. Taking different types of monoids, we obtain different types of collections, as in the table below:

Type of collections Type of monoids
list monoid
finite multiset commutative monoid
finite set idempotent commutative monoid
finite permutation idempotent non-commutative monoid

I/O monad

In purely functional languages such as Haskell, functions cannot have any externally visible side effects as part of the function semantics. 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.[18] In the Haskell notation, a value of type IO a represents an operation that, when performed, produces a value of type a.

We can think of a value of type IO as an action that takes as its argument the current state of the world, and will return a new world where the state has been changed according to the function's return value. For example, the functions doesFileExist and removeFile in the standard Haskell library have the following types

doesFileExist :: FilePath -> IO Bool
removeFile :: FilePath -> IO ()

So, one can think of removeFile as a function that, given a FilePath, returns an IO action; this operation will ensure that the world, in this case the underlying file system, won't have a file named by that FilePath when it gets executed. Here, the IO internal value is of type () which means that the caller does not care about any other outcomes. On the other hand, in doesFileExist, the function returns an IO action which wraps a boolean value, True or False; this conceptually represents a new state of the world where the caller knows for certain whether that FilePath is present in the file system or not at the time of the action is performed. The state of the world managed in this way can be passed from operation to operation, thus defining a series of operations which will be applied in order as steps of state changes. This process is similar to how a temporal logic represents the passage of time using only declarative propositions. The following example clarifies in detail how this chaining of operations occurs in a program, again using Haskell.

We would like to be able to describe all of the basic types of I/O operations, e.g. write text to standard output, read text from standard input, read and write files, send data over networks, etc. In addition, we need to be able to compose these primitives to form larger programs. For example, we would like to be able to write:

main :: IO ()
main = do
  putStrLn "What is your name?"
  name <- getLine
  putStrLn ("Nice to meet you, " ++ name ++ "!")

How can we formalize this intuitive notation? To do this, we need to be able to perform some basic operations with I/O operations:

  • We should be able to sequence two I/O operations together. In Haskell, this is written as an infix operator >>, so that putStrLn "abc" >> putStrLn "def" is an I/O operation that prints two lines of text to the console. The type of >> is IO aIO bIO b, meaning that the operator takes two I/O operations and returns a third that sequences the two together and returns the value of the second.
  • We should have an I/O operation which does nothing. That is, it returns a value but has no side effects. In Haskell, this operation constructor is called return; it has type aIO a.
  • More subtly, we should be able to determine our next operation based on the results of previous operations. To do this, Haskell has an operator >>= (pronounced bind) with type IO a → (aIO b) → IO b. That is, the operand on the left is an I/O operation that returns a value of type a; the operand on the right is a function that can pick an I/O operation based on the value produced by the operation on the left. The resulting combined operation, when performed, performs the first operation, then evaluates the function with the first operation's return value, then performs the second operation, and finally returns the second operation's value.
An example of the use of this operator in Haskell would be getLine >>= putStrLn, which reads a single line of text from standard input and echoes it to standard output. Note that the first operator, >>, is just a special case of this operator in which the return value of the first operation is ignored and the selected second operation is always the same.

It is not necessarily obvious that the three preceding operations, along with a suitable primitive set of I/O operations, allow us to define any program action whatsoever, including data transformations (using lambda expressions), if/then control flow, and looping control flows (using recursion). We can write the above example as one long expression:

main =
  putStrLn "What is your name?" >> 
  getLine >>= \name ->
  putStrLn ("Nice to meet you, " ++ name ++ "!")

The pipeline structure of the bind operator ensures that the getLine and putStrLn operations get evaluated only once and in the given order, so that the side-effects of extracting text from the input stream and writing to the output stream are correctly handled in the functional pipeline. This remains true even if the language performs out-of-order or lazy evaluation of functions.

Environment monad

An environment monad (also called a reader monad and a function monad) allows a computation to depend on values from a shared environment. The monad type constructor maps a type T to functions of type ET, where E is the type of the shared environment. The monad functions are:

The following monadic operations are useful:

The ask operation is used to retrieve the current context, while local executes a computation in a modified subcontext. As in a state monad, computations in the environment monad may be invoked by simply providing an environment value and applying it to an instance of the monad.

State monads

A state monad allows a programmer to attach state information of any type to a calculation. Given any value type, the corresponding type in the state monad is a function which accepts a state, then outputs a new state (of type s) along with a return value (of type t). This is similar to an environment monad, except that it also return a new state, and thus allows modeling a mutable environment.

type State 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 m so that it applies f to its result.
m >>= f = \r -> let (x, s) = m r in (f x) s

Useful state operations include:

get = \s -> (s, s) -- Examine the state at this point in the computation.
put s = \_ -> ((), s) -- Replace the state.
modify f = \s -> ((), f s) -- Update the state

Another operation applies a state monad to a given initial state:

runState :: State s a -> s -> (a, s)
runState t s = t s

do-blocks in a state monad are sequences of operations that can examine and update the state data.

Informally, a state monad of state type S maps the type of return values T into functions of type , where S is the underlying state. The return and bind function are:

.

From the category theory point of view, a state monad is derived from the adjunction between the product functor and the exponential functor, which exists in any cartesian closed category by definition.

Writer monad

The writer monad allows a program to compute various kinds of auxiliary output which can be "composed" or "accumulated" step-by-step, in addition to the main result of a computation. It is often used for logging or profiling. Given the underlying type T, a value in the writer monad has type W × T, where W is a type endowed with an operation satisfying the monoid laws. Namely, W has a binary operation, (a,b) a*b, which is associative, (a*b)*c = a*(b*c), and has a neutral element ε with the property x*ε = ε*x = x for all x.

The monad functions are simply:

where ε and * are the identity element of the monoid W and its associative operation, respectively.

In JavaScript, a writer instance can be expressed as a two-element array, in which the first element is an arbitrary value and the second element is an array that collects extra information.

const writer = [value, []];

The array brackets work here as the monad's type constructor, creating a value of the monadic type for the Writer monad from simpler components (the value in position 0 of the array, and the log array in position 1).

unit (used in place of return, which is a reserved word in JavaScript) creates a new writer instance from a basic value, with an empty accumulator array attached to it.

const unit = value => [value, []];

bind applies a function to a writer instance, and returns a new writer instance composed of the result of the application, and the algebraic sum of the initial and new accumulators.

const bind = (writer, transform) => {
    const [value, log] = writer;
    const [result, updates] = transform(value);
    return [result, log.concat(updates)];
};

pipeline is an auxiliary function that concatenates a sequence of binds applied to a list of functions.

const pipeline = (writer, ...transforms) =>
    transforms.reduce(bind, writer);

Examples of functions that return values of the type expected by the above writer monad:

const squared = x => [x * x, [`${x} was squared.`]];

const halved = x => [x / 2, [`${x} was halved.`]];

Finally, an example of using the monad to build a pipeline of mathematical functions with debug information on the side (that is, an array of debug information is concatenated, and returned with the result, as well):

pipeline(unit(4), squared, halved); // [8, ['16 was squared.', '8 was halved.']]

Continuation monad

A continuation monad with return type maps type into functions of type . It is used to model continuation-passing style. The return and bind functions are as follows:

The call-with-current-continuation function is defined as follows:

Others

Other concepts that researchers have expressed as monads include:

Free monads

Free monads are similar to free monoids, in that they, intuitively speaking, are generic structures that fulfill the monad (monoid) laws without depending on the type in question.

For any type t, the free monoid of t is [t], with ++ as the associative binary operation and [] as the unit element. In Haskell, we can write this as:

instance Functor [] where
   fmap _ [] = []
   fmap fun (x:xs) = fun x : fmap fun xs

instance Monoid [t] where
   mappend xs ys = xs ++ ys
   mempty = []

Whereas in a concrete monoid, one could add the values t1,t2,...,tn with its binary operation; in [], they are simply concatenated into [t1,t2,...,tn], signifying that they "belong together". What that "belonging together" means, however, is left unspecified.

The free monad is based on the same idea. If we take List t = Nil | Cons t (List t) and insert a Functor into it, we get the free monad:

data Free f a = Return a | Bind (f (Free f a))

instance Functor f => Functor (Free f) where
   fmap fun (Return x) = Return (fun x)
   fmap fun (Bind x) = Bind (fmap (fmap fun) x)

instance Functor f => Monad (Free f) where
   return x = Return x
   Return x >>= fun = fun x
   Bind x >>= fun = Bind (fmap (>>= fun) x)

Unlike List, which stores a list of values, Free stores a list of functors, wrapped around an initial value. Accordingly, the Functor and Monad instances of Free do nothing other than handing a given function down that list with fmap.

Comonads

Comonads are the categorical dual of monads. They are defined by a type constructor W T and two operations: extract with type W TT for any T, and extend with type (W TT' ) → W T → W T' . The operations extend and extract are expected to satisfy these laws:

Alternatively, comonads may be defined in terms of operations fmap, extract and duplicate. The fmap and extract operations define W as a copointed functor. The duplicate operation characterizes comonads: it has type W T → W (W T) and satisfies the following laws:

The two formulations are related as follows:

Whereas monads could be said to represent side-effects, a comonad W represents a kind of context. The extract functions extracts a value from its context, while the extend function may be used to compose a pipeline of "context-dependent functions" of type W AB.

Identity comonad

The identity comonad is the simplest comonad: it maps type T to itself. The extract operator is the identity and the extend operator is function application.

Product comonad

The product comonad maps type T into tuples of type , where C is the context type of the comonad. The comonad operations are:

Function comonad

The function comonad maps type T into functions of type , where M is a type endowed with a monoid structure. The comonad operations are:

where ε is the identity element of and * is its associative operation.

Costate comonad

The costate comonad maps a type T into type , where S is the base type of the store. The comonad operations are:

See also

  • Arrows in functional programming – whereas monads generalize the results of a computation to effects, arrows further generalize the inputs similarly
  • Aspect-oriented programming – a paradigm to increase modularity by isolating secondary or supporting functionality
  • Effect system – an alternative way of describing side effects as types
  • Inversion of control – the abstract principle of calling specific functions from a reusable software entity
  • Monad transformers – which allow monads to be composed in a modular and convenient way
  • Uniqueness types - an alternative way of dealing with side-effects in functional languages
  • xmonad – an Xwindows tiling windows manager programmed in Haskell using a monad design pattern

Notes

  1. A type constructor is not the same as an object-oriented constructor; it does not perform any operations but just provides a specification to the type-system, more akin to a type signature.
  2. unit is arguably the closest in spirit to an object-oriented constructor.
  3. Keep in mind that the output of a function, monadic or not, does not necessarily have the same type as the input.
  4. Technically, bind must be strictly associative once the functions involved are given as lambda expressions. This is because, if one is being precise, a monad's bind operation corresponds to abstraction within the lambda calculus, a distinct rule from function application.
  5. Technically, the monad is not required to preserve the underlying type. For example, the trivial monad in which there is only one polymorphic value which is produced by all operations satisfies all of the axioms for a monad. Conversely, the monad is not required to add any additional structure; the identity monad, which simply preserves the original type unchanged, also satisfies the monad axioms and is useful as a recursive base for monad transformers.

References

  1. Lippert, Eric. "Monads, part one". Retrieved 6 September 2013.
  2. 1 2 3 4 5 O'Sullivan, Bryan; Goerzen, John; Stewart, Don (2009). Real World Haskell. O'Reilly. chapter 14.
  3. 1 2 3 Moggi, Eugenio (1991). "Notions of computation and monads" (PDF). Information and Computation. 93 (1): 55–92. CiteSeerX 10.1.1.158.5275.
  4. 1 2 3 Wadler, Philip (June 1990). Comprehending Monads. ACM Conference on LISP and Functional Programming. Nice, France. CiteSeerX 10.1.1.33.5381.
  5. 1 2 3 4 5 Wadler, Philip (January 1992). The essence of functional programming. 19th Annual ACM Symposium on Principles of Programming Languages. Albuquerque, New Mexico. CiteSeerX 10.1.1.38.9516.
  6. "(Haskell) base: Basic libraries". Retrieved 7 October 2018.
  7. "Monad (sans metaphors)". Retrieved 7 October 2018.
  8. "Monad - HaskellWiki". Retrieved 7 October 2018.
  9. "What a Monad is not". 7 October 2018.
  10. De Meuter, Wolfgang (1997). Monads as a theoretical foundation for AOP (PDF). International Workshop on Aspect Oriented Programming at ECOOP. Jyväskylä, Finland. CiteSeerX 10.1.1.25.8262.
  11. Moggi, Eugenio (June 1989). Computational lambda-calculus and monads (PDF). Fourth Annual Symposium on Logic in computer science. Pacific Grove, California. CiteSeerX 10.1.1.26.2787.
  12. Piponi, Dan (August 7, 2006). "You Could Have Invented Monads! (And Maybe You Already Have.)". A Neighborhood of Infinity.
  13. "Monad laws". HaskellWiki. haskell.org. Retrieved 2011-12-11.
  14. "Functors, Applicative Functors and Monoids". learnyouahaskell.com.
  15. "Some Details on F# Computation Expressions". Retrieved 9 October 2018.
  16. "Do notation considered harmful - HaskellWiki". Retrieved 12 October 2018.
  17. How to make Data.Set a monad shows an implementation of the Set restricted monad in Haskell
  18. Peyton Jones, Simon L.; Wadler, Philip. . Conference record of the Twentieth Annual ACM SIGPLAN-SIGACT Symposium on Principles of Programming Languages, Charleston, South Carolina. 1993

Haskell monad tutorials

  • Monad Tutorials Timeline Probably the most comprehensive collection of links to monad tutorials, ordered by date.
  • Piponi, Dan (August 7, 2006). "You Could Have Invented Monads! (And Maybe You Already Have.)". A Neighborhood of Infinity. — The most famous "blog post" tutorial.
  • Yorgey, Brent (12 March 2009). "The Typeclassopedia" (PDF). The Monad.Reader (13): 17–68. — An attempt to explain all of the leading typeclasses in Haskell in an elementary way, with monadic functors considered as only one form, best understood by comparison with others: e.g., the more general idea of a "Functor" as something you can map over; "Applicative" functors, and so forth; contains an extensive bibliography.
  • Yorgey, Brent (January 12, 2009). "Abstraction, intuition, and the "monad tutorial fallacy"". blog :: Brent -> [String]. WordPress.com. — Opposes the idea of making a tutorial about monads in particular.
  • What a Monad is not deals with common misconceptions and oversimplifications in a humorous way.
  • beelsebob (March 31, 2009). "How you should(n't) use Monad". No Ordering. WordPress.com. — Takes a similar point of view, locating monads in a much wider array of Haskell functor classes, of use only in special circumstances.
  • Vanier, Mike (July 25, 2010). "Yet Another Monad Tutorial (part 1: basics)". Mike's World-O-Programming. LiveJournal. — An extremely detailed set of tutorials, deriving monads from first principles.
  • "A Fistful of Monads". An explanation of Monads, building on the concepts of Functors, Applicative Functors and Monoids discussed in the previous chapter.
  • Functors, Applicatives and Monads in Pictures. A humorous beginner's guide to monads.

Older tutorials

  • All About Monads
  • Haskell Wiki: Monads as Computation
  • Haskell Wiki: Monads as Containers
  • Norvell, Theodore. "Monads for the Working Haskell Programmer". Memorial University of Newfoundland.
  • Klinger, Stefan (15 December 2005). "The Haskell Programmer's Guide to the IO Monad — Don't Panic" (PDF) (5–54). Centre for Telematics and Information Technology, University of Twente. ISSN 1381-3625.
  • Turoff, Adam (August 2, 2007). "Introduction to Haskell, Part 3: Monads". ONLamp. O'Reilly Media.
  • Monads A monad tutorial providing examples of non-trivial monads apart from the conventional IO/Maybe/List/State monads.
  • Söylemez, Ertugrul (2010-07-11). "Understanding Haskell Monads".

Other documentation

  • van Tuyl, Henk-Jan (2010-02-27). "A tour of the Haskell monad functions".
  • Moggi, Eugenio. "Notions of computation and monads" (PDF). — The original paper suggesting use of monads for programming
  • Wadler, Philip (August 2001). "Monads for functional programming" (PDF). University of Glasgow. — Describes monads in Haskell (before they were implemented)

Scala monad tutorials

  • League, Chris (July 12, 2010). Monadologie: Professional Help for Type Anxiety (flv) (Tech talk). New York City: New York Scala Enthusiasts.
  • Morris, Tony (June 22, 2010). "Understanding Monads using Scala (Part 1)". λ Tony’s blog λ.
  • Iry, James (September 18, 2007). "Monads are Elephants".
  • Meredith, Gregory (April 25, 2010). "Pro Scala: Monadic Design Patterns for the Web" (PDF) (1st ed.). p. 300.


This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.