πŸ”— Monad Tutorial & Playground

Understand monads visually β€” bind chains, type flows, and interactive exercises

Option Result List State Monad Laws
πŸ“– Learn
πŸ” Visualize
πŸ§ͺ Playground
βš–οΈ Laws
✏️ Exercises
πŸ“Š Compare

What Is a Monad?

A monad is a design pattern for chaining computations that carry extra context (failure, multiple results, state, etc.). In OCaml, a monad provides:

return (pure/unit)

Wraps a plain value into the monadic context.

val return : 'a -> 'a t
(* Example: Some 42, Ok "hello", [1; 2; 3] *)

bind (>>=)

Chains a monadic value through a function that returns a new monadic value. This is the core operation.

val bind : 'a t -> ('a -> 'b t) -> 'b t
(* Unwrap β†’ Apply function β†’ Rewrap *)

Why Not Just Use Functions?

Without monads, you'd write nested pattern matches for every step:

(* Without monads β€” deeply nested *)
match parse_int s with
| None -> None
| Some n ->
  match safe_div 100 n with
  | None -> None
  | Some r -> Some (string_of_int r)

(* With monads β€” clean chain *)
parse_int s >>= safe_div 100 >>= fun r -> return (string_of_int r)

Four Common Monads

πŸ”Έ Option Monad

Chains computations that might fail (return None). Short-circuits on first None.

let bind m f = match m with
  | None   -> None
  | Some x -> f x

let (>>=) = bind
let return x = Some x

πŸ”Ή Result Monad

Like Option but carries error information. Short-circuits on first Error.

let bind m f = match m with
  | Error e -> Error e
  | Ok x    -> f x

let (>>=) = bind
let return x = Ok x

πŸ”» List Monad

Models non-deterministic computation. Each step can produce multiple results.

let bind m f = List.concat_map f m

let (>>=) = bind
let return x = [x]

πŸ”Ί State Monad

Threads state through a computation without explicit state passing.

type ('a, 's) state = 's -> 'a * 's

let bind m f = fun s ->
  let (a, s') = m s in
  f a s'

let return x = fun s -> (x, s)
let get = fun s -> (s, s)
let put s' = fun _ -> ((), s')

Bind Chain Visualizer

Pick a monad and see how values flow through a bind chain step by step.

Monad: Scenario:

πŸ§ͺ Interactive Bind Chain Builder

Build a chain of operations and see the result. Add steps, change the starting value, and watch the data flow.

Monad: Start:
Click "Evaluate" to see the result...

The Three Monad Laws

Every monad must satisfy these laws. They ensure bind and return behave predictably.

1. Left Identity

return a >>= f ≑ f a

Wrapping a value and immediately binding is the same as just calling the function.

(* Option: *)
Some 5 >>= (fun x -> Some (x + 1))
  = (fun x -> Some (x + 1)) 5
  = Some 6  (* βœ“ *)

2. Right Identity

m >>= return ≑ m

Binding with return does nothing β€” it's a no-op.

(* Option: *)
Some 5 >>= (fun x -> Some x)
  = Some 5  (* βœ“ *)

None >>= (fun x -> Some x)
  = None  (* βœ“ *)

3. Associativity

(m >>= f) >>= g ≑ m >>= (fun x -> f x >>= g)

The order you group binds doesn't matter β€” they compose the same way.

(* Both produce the same result: *)
(Some 5 >>= double) >>= safe_sqrt
Some 5 >>= (fun x -> double x >>= safe_sqrt)
(* Both = Some ~3.16 βœ“ *)

βš–οΈ Law Verifier

Pick a monad and value to verify all three laws hold.

Monad: Value:
Click "Verify" to check all three laws...

Exercises

Test your understanding. Fill in the expected output for each expression.

Monad Comparison

MonadContextreturn xbind None/Error/[]Use Case
OptionMight be absentSome x→ None (short-circuit)Nullable values, lookups
ResultMight fail with infoOk x→ Error e (propagate)Validation, IO, parsing
ListMultiple possibilities[x]β†’ [] (no results)Search, permutations
StateThreading statefun s β†’ (x,s)N/A (always succeeds)Counters, accumulators

When to Use Which?

Decision Guide

Can it be absent? β†’ Option

Can it fail with a reason? β†’ Result

Can there be multiple answers? β†’ List

Do you need to thread state? β†’ State

Side effects + sequencing? β†’ IO (Lwt / Async in OCaml)

Real-World OCaml Equivalents

(* Option: built-in *)
Option.bind (Some 42) (fun x -> Some (x + 1))

(* Result: built-in since OCaml 4.08 *)
Result.bind (Ok 42) (fun x -> Ok (x + 1))

(* List: List.concat_map *)
List.concat_map (fun x -> [x; x * 2]) [1; 2; 3]

(* Async IO: Lwt library *)
Lwt.bind (Lwt_io.read_line Lwt_io.stdin) (fun line -> ...)

(* let* syntax (OCaml 4.08+) *)
let* x = Some 5 in
let* y = Some 10 in
Some (x + y)