Building Custom Computation Expressions
Return / ReturnFrom return / return! Yield / YieldFrom yield / yield! if without else Combine + Delay Sequencing multiple expressions For / While TryWith / TryFinally / Using MergeSources / BindReturn and! (applicative) Custom keywords like where, select
Resumable code (F# 6) lets builders compile to efficient state machines (this is how task { } is so fast).
// A result builder
type ResultBuilder() =
member _.Bind(m, f) = Result.bind f m
member _.Return(x) = Ok x
member _.ReturnFrom(m: Result<_, _>) = m
member _.Zero() = Ok ()
member _.Combine(m, f) = Result.bind f m
member _.Delay(f: unit -> Result<_, _>) = f
member _.Run(f) = f ()
let result = ResultBuilder()
let parseInt (s: string) =
match System.Int32.TryParse s with
| true, v -> Ok v
| _ -> Error $"Not a number: {s}"
let addStrings a b = result {
let! x = parseInt a
let! y = parseInt b
if y = 0 then return! Error "Second value is zero"
else return x + y
}
addStrings "2" "3" // Ok 5
addStrings "2" "x" // Error "Not a number: x"
// An option builder
type OptionBuilder() =
member _.Bind(m, f) = Option.bind f m
member _.Return(x) = Some x
member _.ReturnFrom(m) = m
let option = OptionBuilder()
let tryDivide x y = if y = 0 then None else Some (x / y)
option {
let! a = tryDivide 100 5
let! b = tryDivide a 2
return a + b
} // Some 30
// A logging builder (Writer-like)
type LoggingBuilder() =
member _.Bind((value, logs: string list), f) =
le
…