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.JavaScriptCombining Flows
Flow.map changes the successful value, Flow.mapError changes the expected error, and Flow.bind runs dependent
work (it is the function form of let!). Flow.zip runs two descriptions one after the other and keeps both values:
> let loadUser (id: int) : Flow<string, string> = if id = 1 then Flow.ok "ada" else Flow.fail $"no user {id}";;
> loadUser 1 |> Flow.map (fun name -> name.ToUpperInvariant()) |> Flow.run ();;
> loadUser 2 |> Flow.mapError (fun message -> message.Length) |> Flow.run ();;
> loadUser 1 |> Flow.bind (fun name -> Flow.ok $"Hello, {name}") |> Flow.run ();;
> Flow.zip (loadUser 1) (Flow.ok 42) |> Flow.run ();;val it: Exit<string,string> = Success "ADA"
val it: Exit<string,int> = Failure (Fail 9)
val it: Exit<string,string> = Success "Hello, ada"
val it: Exit<Tuple<string,int>,string> = Success ("ada", 42)loadUser: int -> Flow<string,string>id: intintAn abbreviation for the CLI type . Basic Types
FlowA flow that requires no environment and can fail with a typed error.
stringAn abbreviation for the CLI type . Basic Types
(=): 'T -> 'T -> boolStructural equality The first parameter. The second parameter. The result of the comparison. 5 = 5 // Evaluates to true 5 = 6 // Evaluates to false [1; 2] = [1; 2] // Evaluates to true (1, 5) = (1, 6) // Evaluates to false
Axial.Flowok: '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.
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")
(|>): '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
map: ('value -> 'next) -> Flow<'env,'error,'value> -> Flow<'env,'error,'next>Transforms the successful value of a flow. If the source fails, the is not executed. The original failure cause is preserved, including typed failures, interruption, and defects. Use map for pure value transformations after an effect has succeeded. A function of type 'value -> 'next to transform the successful value. The source flow of type to transform. A new with the transformed success value of type 'next. let flow = Flow.succeed 1 |> Flow.map (fun x -> x + 1)
name: stringToUpperInvariant: unit -> stringReturns a copy of this object converted to uppercase using the casing rules of the invariant culture. The uppercase equivalent of the current string.
run: '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
mapError: ('error -> 'nextError) -> Flow<'env,'error,'value> -> Flow<'env,'nextError,'value>Maps the error value of a synchronous flow. Transforms the error type of the flow while leaving successful values untouched. Useful for mapping internal errors into public-facing domain errors. The function to transform the error value. The source flow. A with the transformed error type. let flow = Flow.fail "error" |> Flow.mapError (fun err -> err + "!")
message: stringLength: intGets the number of characters in the current object. The number of characters in the current string.
bind: ('value -> Flow<'env,'error,'next>) -> Flow<'env,'error,'value> -> Flow<'env,'error,'next>Sequences a dependent flow after a successful value. This is the flatmap operation for . The continuation only runs when the source flow succeeds, and it receives the successful value. Use bind when the next effect depends on the previous result; use map when the next step is pure. On .NET, a recursive return! through bind does not keep a task per call alive. Work still pending in the source, such as a use or try/finally, lives until the source completes. A function that takes the successful value and returns a new flow. The source flow to sequence. A representing the combined workflow. let flow = Flow.succeed 1 |> Flow.bind (fun x -> Flow.succeed (x + 1))
zip: Flow<'env,'error,'left> -> Flow<'env,'error,'right> -> Flow<'env,'error,('left * 'right)>Runs two flows sequentially and combines their successful values into a tuple. The first flow to run. The second flow to run. A flow that returns a tuple of both successful values. Flow.zip (Flow.succeed 1) (Flow.succeed 2) |> Flow.run ()
Flow.map2 and Flow.map3 combine the successful values directly. Concurrent composition is a separate choice;
use Flow.zipPar only when both branches are safe to run at the same time.
Prefer flow {} for a longer dependent sequence and pipelines for a short transformation. Both create the same Flow.
Related guides
- Composition reference lists mapping, binding, recovery, traversal, and sequential combination functions.
- Fibers introduces explicit child workflows.
- Schedules adds retry and repetition policies without changing the underlying workflow.

