Result and Error Handling
Errors as values make failures explicit in signatures. Reserve exceptions (Module 24) for truly exceptional situations and .NET interop.
// type Result<'T, 'TError> = Ok of 'T | Error of 'TError
type ValidationError =
| EmptyName
| InvalidAge of int
| InvalidEmail of string
let validateName (name: string) =
if System.String.IsNullOrWhiteSpace name then Error EmptyName else Ok name
let validateAge age =
if age < 0 || age > 150 then Error (InvalidAge age) else Ok age
let validateEmail (email: string) =
if email.Contains "@" then Ok email else Error (InvalidEmail email)
type User = { Name: string; Age: int; Email: string }
let createUser name age email =
validateName name
|> Result.bind (fun n ->
validateAge age
|> Result.bind (fun a ->
validateEmail email
|> Result.map (fun e -> { Name = n; Age = a; Email = e })))
createUser "Ana" 30 "[email protected]" // Ok { Name = "Ana"; Age = 30; Email = "[email protected]" }
createUser "" 30 "[email protected]" // Error EmptyName
// Result module
Ok 5 |> Result.map ((+) 1) // Ok 6
Error "bad" |> Result.mapError String.length // Error 3
Ok 5 |> Result.defaultValue 0 // 5 (F# 7+)
Result.isOk (Ok 1) // true (F# 7+)
Ok 1 |> Result.toOpt
…