liveBook · Manning

Free monad

As explained in Functional Design and Architecture: Examples in Haskell

The Free Monad pattern represents a sequence of domain operations as a data structure that can be interpreted independently from execution.

A free monad represents domain actions as a pure, declarative program value rather than running them immediately. Build scenarios from a small domain-specific language, then hand the scenario to an interpreter that performs each action. This separates business logic from effects and implementation details. section 6.2.1 section 6.2.2

The pattern has three parts: a domain eDSL that defines available actions, one or more interpreters that implement those actions, and monadic scenarios that express business logic. Wrapping an algebra in the recursive Free type makes actions sequential and composable while retaining a uniform script type. section 6.2.2 section 6.3.4

Use a free monad when domain logic needs to remain independent of execution:

  • Describe actions without evaluating them, then choose real, test, sequential, concurrent, or environment-specific interpreters later. section 6.2.3
  • Compose dependent actions in familiar monadic notation instead of exposing continuation-passing plumbing in business logic. section 6.2.2 section 6.4.1
  • Treat the language as a functional interface: expose domain meaning while hiding subsystem implementation details. section 2.2.3 section 6.1
  • Keep subsystems loosely coupled by arranging separate free eDSLs hierarchically and lifting lower-level actions into higher-level languages. section 6.4.2

A recipe as a program

A sandwich recipe can start a sandwich, add cheese and salt, and finish it. Each step returns a value needed by the next, yet the whole recipe remains a SandwichRecipe value. An interpreter can later supply ingredients, maintain state, and produce the sandwich. section 6.3.1 section 7.1.1

Listing 2.6 A possible free monadic scenario
script :: Language ()                #1
script = do                          #2
  readThermometer "Garage"
  readThermometer "Near the road"
  readThermometer "House"
  readBarometer "Garage"
  readBarometer "House"
  reportTemperature
  reportAtmospherePressure
  clearData

This scenario records thermometer and barometer reads, reporting, and cleanup as an ordered Language value; execution is deferred to an interpreter. section 2.2.3

Internally, Free has two recursive cases: Pure ends a chain with a result, while Free holds one language action whose continuation leads to the next Free layer. Monad binding replaces the temporary Pure continuation with later work, avoiding uncontrolled growth of nested script types. section 6.3.2 section 6.3.4

How Functional Design and Architecture: Examples in Haskell covers it

How deep it goes
Explains pattern roles, recursive Free and Pure constructors, smart constructors, functor mapping, and bind-based chaining.
Examples
Uses terminal input and output, sandwich construction, hardware-controller setup, sensor reading, and a weather-reading script.
What it assumes
Builds on ADTs, declarative scripts, continuations, and interpretable eDSLs before descending into monads and functors.
What you can do after
Build it from scratch by defining an algebra, functor, Free wrapper, smart constructors, scenarios, and interpreters.
How it connects
Connects eDSLs, ADTs, functors, monads, interpreters, continuations, GADTs, and hierarchical architecture.

Also explained in

Compare how 2 books explain free monad →

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.