043 — Option Bind (and_then)
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
opt.and_then(|x| maybe_f(x)) to chain fallible computationsmap and and_then: map returns U, and_then returns Option<U>and_then is equivalent to map followed by flattenand_then calls to sequence optional operations? in functions returning Option<T> as syntactic sugar for and_thenOption::and_then(f) (monadic bind) to sequence computations that each may return Optionand_then prevents Option<Option<T>> — it "flattens" one level automaticallyCode Example
#![allow(clippy::all)]
// Placeholder — pending conversionKey Differences
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.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 conversionDeep Comparison
OCaml vs Rust: Option Bind
Overview
See the example.rs and example.ml files for detailed implementations.
Key Differences
| Aspect | OCaml | Rust |
|---|---|---|
| Type system | Hindley-Milner | Ownership + traits |
| Memory | GC | Zero-cost abstractions |
| Mutability | Explicit ref | mut keyword |
| Error handling | Option/Result | Result<T, E> |
See README.md for detailed comparison.
Exercises
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).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<User>), (2) finds their primary address (Option<Address>), (3) formats the city name (may be missing). Chain with and_then.Option: (1) left identity, (2) right identity, (3) associativity. Use concrete values and simple functions.flatten<T>(opt: Option<Option<T>>) -> Option<T> using and_then — notice that opt.and_then(|x| x) is the definition of monadic join.