Pre-1.0 docs. FsFlow is still on the next documentation line, so APIs and examples may change before 1.0.

One model from predicate checks to task execution

A single model for Result-based programs in F#.

Write predicate checks once. Keep fail-fast logic in Result, accumulate multiple failures with Validation, then lift the same logic into Flow when the boundary needs environment access, async work, task interop, cancellation, or runtime policy.
Check once, lift later
type RegistrationError =
    | EmailMissing
    | UserNotFound

let validateEmail (email: string) : Result<string, RegistrationError> =
    email
    |> Check.notBlank
    |> Check.orError EmailMissing

type User =
    { Email: string }

type Api =
    { LoadUser: int -> Task<Result<User, RegistrationError>> }

type Clock =
    { UtcNow: DateTimeOffset }

let readVerifiedEmail userId =
    flow {
        let! user = Env<Api> (_.LoadUser userId)
        let! checkedAt = Env<Clock> _.UtcNow
        let! email = validateEmail user.Email

        return email, checkedAt
    }