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 Environment
There is no container and no registration step. 'env is an ordinary type parameter, and the value you supply is an
ordinary value.
> (Flow.envWith (fun environment -> environment * 2) : Flow<int, Never, int>) |> Flow.run 21;;val it: Exit<int,Never> = Success 42Axial.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())
environment: int(*): ^T1 -> ^T2 -> ^T3Overloaded multiplication operator The first parameter. The second parameter. The result of the operation. 8 * 6 // Evaluates to 48
Axial.Flow`3intAn abbreviation for the CLI type . Basic Types
Axial.NeverRepresents an error channel that cannot occur.
(|>): '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
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
The environment here is an int. Flow does not require a record, an interface, or a service. It hands your function
whatever value you passed to Flow.run.
What the functions do
Flow.envWith runs a function against the environment and continues with the result. _.Name is F# shorthand
for fun environment -> environment.Name, so Flow.envWith _.Name is the same thing written shorter:
> type Person = { Name: string; Age: int };;
> (Flow.envWith _.Name : Flow<Person, Never, string>) |> Flow.run { Name = "Ada"; Age = 36 };;val it: Exit<string,Never> = Success "Ada"Core_05-dependencies_01-the-environment.md_fsharp-2.PersonName: stringstringAn abbreviation for the CLI type . Basic Types
Age: intintAn abbreviation for the CLI type . Basic Types
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: PersonAxial.Flow`3Axial.NeverRepresents an error channel that cannot occur.
(|>): '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
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
The other environment functions:
| Function | What it does |
|---|---|
Flow.envWith projection |
Runs projection against the environment, continues with its result |
Flow.env |
Continues with the environment value itself |
Flow.localEnv change |
Runs a flow against a different environment computed by change |
Flow.localEnv is how a workflow needing a small environment runs inside one that has more:
> type Person = { Name: string; Age: int };;
> let nameLength () : Flow<string, Never, int> = Flow.envWith (fun name -> name.Length);;
> nameLength () |> Flow.localEnv (fun (person: Person) -> person.Name) |> Flow.run { Name = "Ada"; Age = 36 };;val it: Exit<int,Never> = Success 3Core_05-dependencies_01-the-environment.md_fsharp-3.PersonName: stringstringAn abbreviation for the CLI type . Basic Types
Age: intintAn abbreviation for the CLI type . Basic Types
nameLength: unit -> Flow<string,Never,int>Axial.Flow`3Axial.NeverRepresents an error channel that cannot occur.
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())
name: stringLength: intGets the number of characters in the current object. The number of characters in the current 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
localEnv: ('outerEnvironment -> 'innerEnvironment) -> Flow<'innerEnvironment,'error,'value> -> Flow<'outerEnvironment,'error,'value>Runs a flow against an environment derived from the outer environment. Use this to embed a smaller workflow inside a larger application environment without changing the smaller workflow's type. The mapping is applied at execution time. This is useful for preserving narrow helper signatures while still running everything from one app boundary. A function that maps the outer environment to the inner environment. The flow to run with the inner environment. A flow that expects the outer environment. let flow = Flow.succeed 1 |> Flow.localEnv (fun outer -> outer)
person: Personrun: '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
Application records
An application environment is usually a record with one field per dependency, and a workflow reads its fields with
Flow.envWith:
Show page 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.type User = { Id: int; Name: string }
type IUserStore =
abstract Load: int -> Result<User, string>
type IAuditLog =
abstract Record: string -> unit
type AppEnv =
{ Users: IUserStore
Audit: IAuditLog }
let loadUser (id: int) : Flow<AppEnv, string, User> =
flow {
let! users = Flow.envWith _.Users
let! audit = Flow.envWith _.Audit
let! user = users.Load id
audit.Record $"loaded {id}"
return user
}
FsLiveDocsGeneratedPage17_DBB10DAB81D5.UserId: intintAn abbreviation for the CLI type . Basic Types
Name: stringstringAn abbreviation for the CLI type . Basic Types
FsLiveDocsGeneratedPage17_DBB10DAB81D5.IUserStoreLoad: IUserStore -> int -> Result<User,string>Microsoft.FSharp.Core.FSharpResult`2Helper type for error handling without exceptions. Choices and Results
FsLiveDocsGeneratedPage17_DBB10DAB81D5.IAuditLogRecord: IAuditLog -> string -> unitunitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
FsLiveDocsGeneratedPage17_DBB10DAB81D5.AppEnvUsers: IUserStoreAudit: IAuditLogloadUser: int -> Flow<AppEnv,string,User>id: intAxial.Flow`3flow: FlowBuilderThe universal flow { } computation expression.
users: IUserStoreAxial.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: AppEnvaudit: IAuditLog_arg3: AppEnvuser: UserLoad: int -> Result<User,string>Record: string -> unitConstruct that record at boot with the live implementations and in tests with fakes: the same record type, different
values. The App Record tutorial builds a complete application record,
shows the boot and test construction, and proves a moved dependency still receives the right value. Larger systems
often define one record per architectural boundary rather than a single application-wide one, and use Flow.localEnv
to move between them; a billing subsystem that cannot see the mailer is a record without a mailer field, enforced by
the compiler rather than by convention.
Related topics
- Choosing an approach: when arguments beat a record, and when a record stops being enough.
- Service contracts: how a package asks for a dependency without knowing your record type.
- Providing the environment: building the value at a host boundary.

