liveBook · Manning

Monad

As explained in Learn Haskell by Example

A monad is an abstraction that sequences computations while encapsulating a computational context.

A monad is a Haskell abstraction for sequencing computations whose next step can depend on a previous result. A monadic value has a type such as m a: it wraps a value of type a in a context represented by m. Monads extend applicatives; every Monad is also an Applicative. section 12.1.5

The need for a monad appears when fixed parser composition is not enough. An applicative parser can combine known steps, but it cannot choose a later parsing path from a value it has already read. Binding makes that data-dependent choice possible. section 12.1.5 section 12.0

The core Monad operations are:

  • (>>=), called bind: takes m a and a function a -> m b, extracts the produced value for that function, and returns its new monadic result. section 12.1.5
  • (>>): sequences two monadic values while discarding the first result. section 12.1.5
  • return: wraps an ordinary value in a monadic value; for Monad instances it serves the role of Applicative pure. section 12.1.5
  • do notation: writes chains of binds in an imperative-looking, readable form. section 12.1.5

Sequencing Maybe values

Binding preserves the context. Starting with Just 1, successive computations can produce Just 2 and then Just 4. Starting with Nothing instead keeps the result Nothing, so later calculations do not produce a value. The same pattern can define a generic monadic addition function: bind each input, then return their sum. section 12.1.5

A parser Monad runs one parser, then feeds its remaining input and parsed value into the next parser. If the first parser fails, it returns that error; if it succeeds, the continuation selects and runs the next parser. This permits parsers whose structure depends on parsed data. section 12.1.5

Parsing a conditional PNM header

A PNM header parser first reads a magic number, width, and height. It then uses an if expression: P1 and P4 headers return Nothing for the maximum value, while other formats parse an integer and wrap it in Just. The final Header is returned after those dependent steps. section 12.1.5

Listing 12.13 A Monad instance for the parser type
instance Monad Parser where
  return = pure        #1
  (>>=) p f =
    Parser $ \t ->
      case runParser p t of     #2
        Left msg -> Left msg             #3
        Right (rest, x) -> runParser (f x) rest    #4

The Parser Monad instance makes sequencing concrete: a successful parser passes its remaining text and value to the next parser, while a failure is retained. section 12.1.5

How Learn Haskell by Example covers it

How deep it goes
Defines Monad operations, demonstrates Maybe and do notation, and implements a Monad instance for a custom parser.
Examples
Uses Maybe calculations, monadic addition, a Hello World parser, integer parsing, and conditional PNM headers.
What it assumes
Introduces monads after applicatives when data-dependent parser choices become necessary.
What you can do after
Build it from scratch by defining bind behavior for a parser and using do notation for dependent parsing.
How it connects
Connects Monad to Applicative, Functor, Maybe, Parser, do notation, and pure functions.

Also explained in

Compare how 6 books explain monad →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Haskell by Example. The section links point to the parts of the book it draws on.