Module C1.08
Option, Result & railway errors
No nulls, no exceptions for control flow — F# puts absence and failure in the type.
F# almost never uses null, and it does not throw exceptions for ordinary
control flow. Instead, absence and failure become ordinary values, carried by
two small union types: Option — Some for "a value is
here", None for "it is not" — and Result —
Ok for success, Error for failure with a reason attached.
Because they are unions, a program reads them with match and threads them with
map and bind. This module covers them in three dives —
Option for what might be missing, Result for what might fail,
and the railway-oriented style that wires failable steps into a pipeline that stops at the
first error.
Two unions for the things that go wrong
Most languages reach for null when a value might be absent, and for an exception
when an operation might fail. Both are off to the side of the type: a function returns int,
and the caller cannot tell from the signature that it might also return nothing, or throw. F# folds both cases
back into the return type with two unions from the C1.06 toolbox.
The first dive covers Option — the type-safe replacement for
null. A function that might not produce a value returns
Some x or None, and the caller must account for both before
reaching the x inside. The second covers Result,
which is the same shape with a reason on the failing side: Ok x or
Error e. The third composes failable steps into a railway: each step
returns a Result, and the first Error switches the whole
computation onto the error track. Select a dive below to read its summary and the one idea it adds.
The three dives · select one
Option<'T> is Some of 'T | None — the type-safe replacement for null. List.tryFind and Map.tryFind return it; Option.map and Option.bind transform the inside without unwrapping.
Open this dive · or pick another above
Absence and failure are not special cases bolted onto the type — they are two more values a function can return, read like any other.
The three dives
Read them in order. Each stands on valid, runnable F#: every Some,
None, Ok, and Error below was typed
into dotnet fsi and echoes exactly what the page shows.
Option
Some / None — the replacement for null. List.tryFind, Map.tryFind, Option.map, Option.bind, Option.defaultValue.
- absencemodel a missing value, thread it without unwrapping
Result
Ok / Error — failure that carries a reason. Result.map, Result.mapError, Result.bind, and the value-restriction detail.
- failurecarry the why alongside the what
Railway-oriented errors
A two-track pipeline: each step returns Result, and the first Error switches onto the error track and skips the rest.
- pipelinecompose failable steps that short-circuit
References
Sources
- Microsoft — F# documentation — options, results, and error handling without exceptions.
- FSharp.Core API reference — the
OptionandResultmodules:map,bind,defaultValue,mapError. - The F# Language Specification — union types, pattern matching, and the value restriction.
Related in this course
- C1.08.1 — Option — absence as an ordinary value.
- C1 — F# Language — the chapter this module sits in.
- Elixir — Purity — the same idea on the BEAM: failure returned as
{:ok, _}/{:error, _}, not raised.