ExamplesBy LevelBy TopicLearning Paths
043 Intermediate

043 — Option Bind (and_then)

Functional Programming

Tutorial Video

Text description (accessibility)

This video demonstrates the "043 — Option Bind (and_then)" functional Rust example. Difficulty level: Intermediate. Key concepts covered: Functional Programming. `Option::and_then` (also called "bind" in Haskell/OCaml) is the monadic sequencing operation for `Option`. Key difference from OCaml: 1. **Naming**: Rust calls it `and_then` (method), Haskell `>>=`, OCaml `Option.bind`. All are the same operation: `T

Tutorial

The Problem

Option::and_then (also called "bind" in Haskell/OCaml) is the monadic sequencing operation for Option. Where map(f) applies f: T -> U and wraps in Some, and_then(f) applies f: T -> Option<U> — the function itself decides whether to return Some or None. This prevents double-wrapping: map on an Option-returning function produces Option<Option<U>>; and_then flattens it to Option<U>.

and_then is the essence of the option monad: "do this, but only if the previous step succeeded". It enables sequential fallible computations without nesting: find_user(id).and_then(|u| find_account(u.id)).and_then(|a| check_balance(a)) — each step may fail, and failure propagates automatically.

🎯 Learning Outcomes

  • • Use opt.and_then(|x| maybe_f(x)) to chain fallible computations
  • • Understand the difference between map and and_then: map returns U, and_then returns Option<U>
  • • Recognize that and_then is equivalent to map followed by flatten
  • • Chain multiple and_then calls to sequence optional operations
  • • Use ? in functions returning Option<T> as syntactic sugar for and_then
  • • Use Option::and_then(f) (monadic bind) to sequence computations that each may return Option
  • • Understand that and_then prevents Option<Option<T>> — it "flattens" one level automatically
  • Code Example

    #![allow(clippy::all)]
    // Placeholder — pending conversion

    Key Differences

  • Naming: Rust calls it and_then (method), Haskell >>=, OCaml Option.bind. All are the same operation: T -> Option<U> applied to Option<T> producing Option<U>.
  • **? operator**: Rust's ? in a function returning Option is and_then spelled differently — x? means "extract from Some, or return None early". OCaml needs ppx_let for let* syntax.
  • **map vs and_then choice**: Use map when the transformation cannot fail (|x| x * 2). Use and_then when the transformation is itself fallible (|x| safe_div(x, 2)).
  • **flatten**: opt.map(f).flatten() is equivalent to opt.and_then(f). Rust provides both; use and_then directly as it is more efficient.
  • Monadic bind: and_then is monadic bind (>>=) for Option. It sequences computations that may fail: "if the previous step produced a value, run the next step with it; otherwise propagate None."
  • **flat_map vs bind:** Rust calls it and_then; Haskell calls it >>=; Scala calls it flatMap. All are the same operation. The name and_then is chosen because it reads well: "do this, and then do that."
  • **Option.bind in OCaml:** Option.bind opt f = match opt with None -> None | Some x -> f x. The let* syntax sugar (with ppx_let) allows let* x = opt in f x — reads like imperative code.
  • **flat_map equivalence:** opt.and_then(f) is identical to opt.map(f).flatten() when f returns Option<U>. The name and_then reflects sequential dependency: "do this, AND THEN do that."
  • OCaml Approach

    OCaml's Option.bind opt f: let bind opt f = match opt with None -> None | Some x -> f x. The |> pipe with Option.bind: opt |> Option.bind safe_div. OCaml 4.08+ provides Option.bind. With ppx_let: let* x = find_user id in let* acc = find_account x.id in check_balance acc — this is the monadic let syntax that makes sequenced options look like sequential code.

    Full Source

    #![allow(clippy::all)]
    // Placeholder — pending conversion

    Deep Comparison

    OCaml vs Rust: Option Bind

    Overview

    See the example.rs and example.ml files for detailed implementations.

    Key Differences

    AspectOCamlRust
    Type systemHindley-MilnerOwnership + traits
    MemoryGCZero-cost abstractions
    MutabilityExplicit refmut keyword
    Error handlingOption/ResultResult<T, E>

    See README.md for detailed comparison.

    Exercises

  • Parse chain: Write parse_and_double(s: &str) -> Option<i32> that parses a string to an integer and doubles it, returning None if parsing fails. Use s.parse::<i32>().ok().map(|x| x * 2).
  • Nested lookup: Write lookup_nested(outer: &HashMap<i32, HashMap<i32, String>>, k1: i32, k2: i32) -> Option<&String> using outer.get(&k1).and_then(|inner| inner.get(&k2)).
  • Option pipeline: Write a function that: (1) finds a user by ID (Option<User>), (2) finds their primary address (Option<Address>), (3) formats the city name (may be missing). Chain with and_then.
  • Monad laws test: Write tests verifying the three monad laws for Option: (1) left identity, (2) right identity, (3) associativity. Use concrete values and simple functions.
  • Flatten via bind: Implement flatten<T>(opt: Option<Option<T>>) -> Option<T> using and_then — notice that opt.and_then(|x| x) is the definition of monadic join.
  • Open Source Repos