liveBook · Manning

Do notation

As explained in Functional Design and Architecture: Examples in Haskell

Do notation is Haskell syntax for expressing a sequence of monadic computations with implicit binding between steps.

Do notation expresses a sequence of monadic computations while hiding repetitive binding and failure-handling mechanics. With Maybe, it replaces nested case expressions: each step either supplies a value for the next binding or stops with Nothing. section 1.5.4

Replacing nested Maybe handling

A user-initial lookup can bind each successful result directly: getUserInitials' key = do; user <- getUser key users; name <- getUserName user; Just (head name). The Maybe monad preserves the same failure behavior without repeating two levels of pattern matching. section 1.5.4

getUserInitials' :: Int -> Maybe Char
getUserInitials' key = do
  user <- getUser key users       #1
  name <- getUserName user        #2
  Just (head name)

Compare the concise do-notation version with the nested case-based implementation to see how monadic behavior removes control-flow boilerplate. section 1.5.4

Do notation also makes functional domain scripts read like imperative workflows while remaining values that an interpreter can execute. A terminal scenario can read two lines and print them back, then support alternate interpreters such as a web interface. section 6.2.2

The design principle is to separate scenario construction from execution:

  • Construct actions as values rather than calling real-world functions directly. section 6.2.2
  • Bind each action’s result to the next step with do notation. section 6.2.2
  • Choose an interpreter later, enabling alternate execution environments and supporting dependency injection or domain-specific languages. section 6.2.2
terminal :: Terminal ()                       #1
terminal = do                                 #2
  line1 <- readLine                           #3
  printLine line1                             #4
  
  line2 <- readLine
  printLine line2

Inspect a free-monadic terminal program whose do-notation sequences reads and prints while leaving interpretation separate. section 6.2.2

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Explains binding through Maybe and Free Monad examples, but defers the broader mechanics of monadic abstractions.
Examples
Uses user lookup with Maybe and a terminal script that reads and echoes two lines.
What it assumes
Assumes familiarity with Maybe results and monadic behavior while illustrating their practical use through concrete workflows.
What you can do after
Apply it via Haskell do-notation to shorten monadic workflows and construct interpretable functional scenarios.
How it connects
Connects Maybe, monads, Free Monad, interpreters, dependency injection, and domain-specific languages.

Also explained in

Compare how 2 books explain do notation →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Functional Design and Architecture: Examples in Haskell. The section links point to the parts of the book it draws on.