Monad (sans metaphors)

From HaskellWiki
Revision as of 08:53, 21 September 2021 by Atravers (talk | contribs)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to navigation Jump to search

Think of a monad as a spacesuit full of nuclear waste in the ocean next to a container of apples. Now, you can't put oranges in the spacesuit or the nuclear waste falls in the ocean, but the apples are carried around anyway, and you just take what you need.

Don Stewart.

Introduction

Many discussions of Haskell monads seek to explain them through the use of a variety of metaphors. This page attempts to simply provide a more technical yet straightforward description of monads as defined by Haskell.

So what is a monad?

In Haskell, a monad is a type constructor with two operations, implementing a standard interface and following a few simple rules:

  • The Monad type class tells you the interface (what operations you've got, and their types),
  • the monad laws tell you what all types implementing that interface should have in common.

The monadic interface gives you two operations:

  • one to stuff things into a monadic thing: return,
  • and one to chain two monadic things together: (>>=).

The chaining explicitly caters for information flowing from the first to the second parameter of (>>=).

The monad laws tell you two useful facts about monadic things thrown together in that way: whatever it is the monad does, anything just thrown into it will take no part in that action, and whichever way you use that chaining operation, the structure of chaining is irrelevant - only the ordering of chained monadic things matters.

There are usually other ways to create "primitive" monadic things, which can be combined into complex monadic structures using the operations of the monadic interface.

There usually is an abstract way to interpret monadic structures built in this way - a run operation of some kind. Examples include:

  • IO: The "primitive monadic things" are basic I/O operations. The run operation exists outside the language, to be applied to Main.main. return puts its argument into a simple IO thing which, if used, merely produces that original argument. (>>=) arranges IO monadic structures sequentially, starting with the leftmost innermost I/O operation in the structure and applying the second argument of (>>=) to the result of executing the first.
  • []: The "primitive monadic things" are lists. The run operation is the identity, i.e the lists are directly exposed as data structures. return creates a singleton list. (>>=) applies its second argument to each element of its first argument and concatenates the results (concatMap).

Sometimes the monadic type provides the run operation as part of its interface:

  • State: The "primitive monadic things" are operations on a state type, returning a result and a state. The run operation is provided by runState, wich applies a (possibly) complex monadic thing to an input state, returning a result and a (modified) state. return returns its parameter, passing its input state unchanged. (>>=) applies its first parameter to the input state, applies its second parameter to the result value and result state of the first.
  • ST: The "primitive monadic things" are operations on an abstract, encapsulated state type. The run operation is provided by runST, which obtains the result of an ST thing, through the use of private state and an extension of the regular Haskell type system. return puts its argument into a simple ST thing which, if used, merely produces that original argument. (>>=) establishes the ordering of ST things by applying its second argument to the result of executing the first.

Original source