Repository F# setup
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.PlatformService
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScriptThe Flow CE
Use flow {} when later work depends on earlier success.
Suppose the block calls these functions:
Shared setup
// Setup for the checked examples on this page.
open System
open System.IO
open System.Threading
open System.Threading.Tasks
open Axial
open Axial.Layers
open Axial.Console
open Axial.FileSystem
open Axial.Hosting
open Axial.Hosting.Browser
open Axial.Hosting.Node
open Axial.PlatformService
open Axial.State
open Axial.Telemetry
open Axial.Telemetry.JavaScript
/// Fails the docs test when an example's result differs from the value shown.
let shouldEqual expected actual =
if actual <> expected then failwithf "Expected %A but got %A" expected actual
SystemIOThreadingTasksAxialLayersConsoleFileSystemHostingBrowserNodePlatformServiceStateTelemetryJavaScriptshouldEqual: 'a -> 'a -> unitexpected: 'aactual: 'a(<>): 'T -> 'T -> boolStructural inequality The first parameter. The second parameter. The result of the comparison. 5 <> 5 // Evaluates to false 5 <> 6 // Evaluates to true [1; 2] <> [1; 2] // Evaluates to false
failwithf: Printf.StringFormat<'T,'Result> -> 'TPrint to a string buffer and raise an exception with the given result. Helper printers must return strings. The formatter. The formatted result. See Printf.failwithf (link: ) for examples.
type User = { Id: int; Name: string }
type AppError = UserNotFound of int
type AppEnv = { Users: Map<int, User>; Audit: ResizeArray<string> }
let loadUser (id: int) : Flow<AppEnv, AppError, User> =
flow {
let! users = Flow.envWith _.Users
match Map.tryFind id users with
| Some user -> return user
| None -> return! Flow.fail (UserNotFound id)
}
let auditUser (user: User) : Flow<AppEnv, AppError, unit> =
Flow.envWith (fun env -> env.Audit.Add $"read {user.Id}")
let greetUser (user: User) : Flow<AppEnv, AppError, string> = Flow.ok $"Hello, {user.Name}"
FsLiveDocsGeneratedPage7_4556FC416C2B.UserId: intintAn abbreviation for the CLI type . Basic Types
Name: stringstringAn abbreviation for the CLI type . Basic Types
FsLiveDocsGeneratedPage7_4556FC416C2B.AppErrorUserNotFoundFsLiveDocsGeneratedPage7_4556FC416C2B.AppEnvUsers: Map<int,User>Microsoft.FSharp.Collections.FSharpMap`2Immutable maps based on binary trees, where keys are ordered by F# generic comparison. By default comparison is the F# structural comparison function or uses implementations of the IComparable interface on key values. See the module for further operations on maps. All members of this class are thread-safe and may be used concurrently from multiple threads.
Audit: ResizeArray<string>ResizeArrayAn abbreviation for the CLI type
loadUser: int -> Flow<AppEnv,AppError,User>id: intAxial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
flow: FlowBuilderThe universal flow { } computation expression.
users: Map<int,User>Axial.FlowenvWith: ('env -> 'value) -> Flow<'env,'error,'value>Projects one value from the current environment. This is the primary way to access app dependencies, configuration, or request metadata stored in env. The projection runs only when the flow is executed, so constructing the flow is still pure and side-effect free. Prefer small projections over passing a large environment deeper into reusable helpers. A function that extracts a value from the environment. A containing the projected value. let currentTime () = Flow.envWith (fun (environment: BaseRuntime) -> environment.Clock.UtcNow())
_arg1: AppEnvMicrosoft.FSharp.Collections.MapModuleContains operations for working with values of type .
tryFind: 'Key -> Map<'Key,'T> -> 'T optionLookup an element in the map, returning a Some value if the element is in the domain of the map and None if not. The input key. The input map. The found Some value or None. Maps are represented as binary trees so this is an O(log n) operation, where n is the number of bindings in the map. let sample = Map [ (1, "a"); (2, "b") ] sample |> Map.tryFind 1 // evaluates to Some "a" sample |> Map.tryFind 3 // evaluates to None
SomeThe representation of "Value of type 'T" The input value. An option representing the value.
user: UserNoneThe representation of "No value"
fail: 'error -> Flow<'env,'error,'value>Same as error. The error value to wrap in a failing flow. A flow that always fails with the provided error. let result = Flow.fail "error" |> Flow.run () // result = Failure (Cause.Fail "error")
auditUser: User -> Flow<AppEnv,AppError,unit>unitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
env: AppEnvAdd: string -> unitAdds an object to the end of the . The object to be added to the end of the . The value can be for reference types.
greetUser: User -> Flow<AppEnv,AppError,string>ok: 'value -> Flow<'env,'error,'value>Creates a successful synchronous flow. The value to wrap in a successful flow. A flow that always succeeds with the provided value.
let! binds a successful value to the name on its left. do! binds a step whose success value is unit.
return! uses another complete Flow as the result of the block:
let greet (userId: int) : Flow<AppEnv, AppError, string> =
flow {
let! user = loadUser userId
do! auditUser user
return! greetUser user
}
greet: int -> Flow<AppEnv,AppError,string>userId: intintAn abbreviation for the CLI type . Basic Types
Axial.Flow`3Represents a cold workflow that reads an environment, returns a typed result, and is executed explicitly through one of its execution members such as ToTask, ToAsync, or RunSynchronously. The type of the environment dependency. The type of the failure value. The type of the success value.
FsLiveDocsGeneratedPage7_4556FC416C2B.AppEnvFsLiveDocsGeneratedPage7_4556FC416C2B.AppErrorstringAn abbreviation for the CLI type . Basic Types
flow: FlowBuilderThe universal flow { } computation expression.
user: UserloadUser: int -> Flow<AppEnv,AppError,User>auditUser: User -> Flow<AppEnv,AppError,unit>greetUser: User -> Flow<AppEnv,AppError,string>The first failure stops the block. do! and return! do not run for a missing user:
let env = { Users = Map [ 1, { Id = 1; Name = "Ada" } ]; Audit = ResizeArray() }
greet 1 |> Flow.run env |> shouldEqual (Exit.Success "Hello, Ada")
greet 2 |> Flow.run env |> shouldEqual (Exit.Failure(Cause.Fail(UserNotFound 2)))
List.ofSeq env.Audit |> shouldEqual [ "read 1" ]
env: AppEnvUsers: Map<int,User>``.ctor``: (int * User) seq -> Map<int,User>Builds a map that contains the bindings of the given IEnumerable. The input sequence of key/value pairs. The resulting map. This is an O(n log n) operation, where n is the number of elements in the sequence. Map [ (1, "a"); (2, "b") ] // evaluates to map [(1, "a"); (2, "b")]
Id: intName: stringAudit: ResizeArray<string>``.ctor``: unit -> unitInitializes a new instance of the class that is empty and has the default initial capacity.
greet: int -> Flow<AppEnv,AppError,string>(|>): 'T1 -> ('T1 -> 'U) -> 'UApply a function to a value, the value being on the left, the function on the right The argument. The function. The function result. let doubleIt x = x * 2 3 |> doubleIt // Evaluates to 6
Axial.Flowrun: 'env -> Flow<'env,'error,'value> -> Exit<'value,'error>Runs the workflow and blocks until the final exit is available. The environment used by the workflow. The workflow to run. The final workflow exit. let exit = workflow |> Flow.run environment
shouldEqual: 'a -> 'a -> unitAxial.Exit`2Represents the final outcome of a workflow execution. The type of the success value. The type of the domain-specific failure value.
SuccessThe workflow completed successfully.
FailureThe workflow failed due to a specific cause.
Axial.Cause`1Represents the cause of a failed workflow. The type of the domain-specific failure value.
FailAn expected domain-specific failure.
UserNotFoundMicrosoft.FSharp.Collections.ListModuleContains operations for working with values of type . Operations for collections such as lists, arrays, sets, maps and sequences. See also F# Collection Types in the F# Language Guide.
ofSeq: 'T seq -> 'T listBuilds a new list from the given enumerable object. The input sequence. The list of elements from the sequence. let inputs = seq { 1; 2; 5 } inputs |> List.ofSeq Evaluates to [ 1; 2; 5 ]. This is an O(n) operation, where n is the length of the sequence.
flow {} also binds Result, Option, ValueOption, Async, and ColdTask. An outer Result.Error enters the
Flow error channel. Raw Task and ValueTask values do not bind directly; use ColdTask for work that should start
with the Flow or an explicit Flow.awaitStarted* function for work already running. The output remains one cold Flow
description until an execution boundary runs it.
Normal F# if, match, for, and while expressions work inside the computation expression.
Go Further
- Flow builder reference lists the values accepted by each computation-expression operation.
- Bind covers bind-site error assignment and mapping when the source error does not already match the workflow.
- Task and Async interop gives the detailed carrier and cancellation rules.

