Repository F# setup
open Reified
open Reified.Refinements
open Reified.Result
open Reified.Schema.Json

Handling errors

The error channel gets the same treatment as the success channel: map it, replace it, or use it to produce a fallback.

open Reified.Result

type SignupError =
    | NameMissing
    | AgeMissing

Changing the error

mapError transforms whatever the error carries. Use it when the existing error holds something worth keeping.

Error NameMissing |> Result.mapError (fun _ -> "name is required")
// Error "name is required"

orError discards the existing error and substitutes yours. Use it when the incoming error carries nothing — the unit from okIf, failIf, or fromTry, or a low-level detail the caller should not see.

Error "index out of range" |> Result.orError NameMissing
// Error NameMissing

Recovering

orElse supplies a fallback result when the first one fails. The fallback is an already-computed value.

(Error AgeMissing: Result<int, SignupError>) |> Result.orElse (Ok 0)
// Ok 0

Ok 36 |> Result.orElse (Ok 0)
// Ok 36

orElseWith computes the fallback from the error, and only on failure. Use it when the fallback is expensive, or when which fallback to use depends on why the first attempt failed.

(Error AgeMissing: Result<int, SignupError>) |> Result.orElseWith (fun _ -> Ok 0)
// Ok 0

Both keep the error type the same. A recovery step that fails with a different error type is not covered here — convert with mapError first so both sides agree.

Choosing between them

Situation Function
the error carries something worth keeping mapError
the error is unit or an internal detail orError
a fallback value is already to hand orElse
the fallback is expensive or depends on the error orElseWith