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.JavaScriptPolicy and verification
Use a Policy to define a named verification rule that a workflow can apply to an input value. Run the rule inside a
workflow with Flow.verify.
A policy has this shape:
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.
Policy<'env, 'error, 'input, 'output>It is an alias for a function:
'env -> 'input -> Result<'output, 'error>The type parameters describe the policy's contract:
'envis the workflow environment that the policy can read.'erroris the expected workflow error returned when verification fails.'inputis the value to verify.'outputis the verified or transformed value returned on success.
Defining a policy does not run a Flow. A policy is a reusable function value. Flow.verify policy input creates a
Flow that supplies the current workflow environment to the policy when the Flow runs. Ok output continues the
workflow, and Error error short-circuits it through the typed error channel.
Define and run a policy
The following policy checks a limit from the workflow environment:
type AppEnv =
{ EnforceLimit: bool
Limit: int }
type OrderError = TooLarge
let withinLimit : Policy<AppEnv, OrderError, int, int> =
fun env count ->
if count <= env.Limit then Ok count
else Error TooLarge
let placeOrder count =
flow {
let! checkedCount =
count
|> Flow.verify withinLimit
return checkedCount
}
FsLiveDocsGeneratedPage13_4556FC416C2B.AppEnvEnforceLimit: boolboolAn abbreviation for the CLI type . Basic Types
Limit: intintAn abbreviation for the CLI type . Basic Types
FsLiveDocsGeneratedPage13_4556FC416C2B.OrderErrorTooLargewithinLimit: Policy<AppEnv,OrderError,int,int>PolicyRepresents an environment-aware requirement that turns an input into either an output or a workflow error. The workflow environment available to the policy. The workflow error produced by the policy. The input value checked by the policy. The output value produced by the policy.
env: AppEnvcount: int(<=): 'T -> 'T -> boolStructural less-than-or-equal comparison The first parameter. The second parameter. The result of the comparison. 5 <= 1 // Evaluates to false 5 <= 5 // Evaluates to true [1; 5] <= [1; 6] // Evaluates to true
OkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
placeOrder: int -> Flow<AppEnv,OrderError,int>flow: FlowBuilderThe universal flow { } computation expression.
checkedCount: int(|>): '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.Flowverify: Policy<'env,'error,'input,'output> -> 'input -> Flow<'env,'error,'output>Creates a flow that verifies an input with an environment-aware policy. When the Flow runs, verify supplies its current environment to the policy. An Ok result succeeds with the policy output. An Error result short-circuits the workflow through its typed error channel. The reusable verification rule to apply. The input value to verify. A cold flow that succeeds or fails with the policy result.
placeOrder 3 |> Flow.run { EnforceLimit = true; Limit = 5 } |> shouldEqual (Exit.Success 3)
placeOrder 9 |> Flow.run { EnforceLimit = true; Limit = 5 } |> shouldEqual (Exit.Failure(Cause.Fail TooLarge))
placeOrder: int -> Flow<AppEnv,OrderError,int>(|>): '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
EnforceLimit: boolLimit: intshouldEqual: '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.
TooLargeFlow.verify is pipe-friendly because it takes the policy first and the input second. The example is equivalent to
Flow.verify withinLimit count.
Adapt an existing function
Use a Policy constructor when you already have a function that returns Result:
| Function | Use it when |
|---|---|
Policy.lift operation mapError |
The operation does not need the environment and its error must be mapped. |
Policy.withError operation error |
The operation does not need the environment and any failure has one workflow error. |
Policy.context operation mapError |
The operation reads the environment and its error must be mapped. |
For example, Policy.withError assigns a workflow error to a validation function whose error is unit:
type RegistrationError = NameRequired
let requireNonBlank (value: string) =
if String.IsNullOrWhiteSpace value then Error() else Ok value
let requireName : Policy<unit, RegistrationError, string, string> =
Policy.withError requireNonBlank NameRequired
let register (name: string) : Flow<RegistrationError, string> =
flow {
let! checkedName = name |> Flow.verify requireName
return checkedName
}
FsLiveDocsGeneratedPage13_4556FC416C2B.RegistrationErrorNameRequiredrequireNonBlank: string -> Result<string,unit>value: stringstringAn abbreviation for the CLI type . Basic Types
System.StringRepresents text as a sequence of UTF-16 code units.
IsNullOrWhiteSpace: string -> boolIndicates whether a specified string is , empty, or consists only of white-space characters. The string to test. if the parameter is or , or if consists exclusively of white-space characters.
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
OkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
requireName: Policy<unit,RegistrationError,string,string>PolicyRepresents an environment-aware requirement that turns an input into either an output or a workflow error. The workflow environment available to the policy. The workflow error produced by the policy. The input value checked by the policy. The output value produced by the policy.
unitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
Axial.PolicyModuleConstructors and combinators for environment-aware workflow requirements.
withError: ('input -> Result<'output,'innerError>) -> 'error -> 'env -> 'input -> Result<'output,'error>Lifts a pure result-returning function and replaces any error with a fixed workflow error.
register: string -> Flow<RegistrationError,string>name: stringFlowA flow that requires no environment and can fail with a typed error.
flow: FlowBuilderThe universal flow { } computation expression.
checkedName: 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.Flowverify: Policy<'env,'error,'input,'output> -> 'input -> Flow<'env,'error,'output>Creates a flow that verifies an input with an environment-aware policy. When the Flow runs, verify supplies its current environment to the policy. An Ok result succeeds with the policy output. An Error result short-circuits the workflow through its typed error channel. The reusable verification rule to apply. The input value to verify. A cold flow that succeeds or fails with the policy result.
register "Ada" |> Flow.run () |> shouldEqual (Exit.Success "Ada")
register " " |> Flow.run () |> shouldEqual (Exit.Failure(Cause.Fail NameRequired))
register: string -> Flow<RegistrationError,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.
NameRequiredCompose policies
Use Policy.compose first second to run two policies from left to right. The second policy receives the successful
output of the first. The first error stops the composition.
let normalizeName : Policy<unit, RegistrationError, string, string> =
Policy.lift (fun (name: string) -> Ok(name.Trim())) id
let normalizedName = Policy.compose requireName normalizeName
normalizeName: Policy<unit,RegistrationError,string,string>PolicyRepresents an environment-aware requirement that turns an input into either an output or a workflow error. The workflow environment available to the policy. The workflow error produced by the policy. The input value checked by the policy. The output value produced by the policy.
unitThe type 'unit', which has only one value "()". This value is special and always uses the representation 'null'. Basic Types
FsLiveDocsGeneratedPage13_4556FC416C2B.RegistrationErrorstringAn abbreviation for the CLI type . Basic Types
Axial.PolicyModuleConstructors and combinators for environment-aware workflow requirements.
lift: ('input -> Result<'output,'innerError>) -> ('innerError -> 'error) -> 'env -> 'input -> Result<'output,'error>Lifts a pure result-returning function and maps its error into the workflow error type.
name: stringOkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
Trim: unit -> stringRemoves all leading and trailing white-space characters from the current object. The string that remains after all white-space characters are removed from the start and end of the current string. If no characters can be trimmed from the current instance, the method returns the current instance unchanged.
id: 'T -> 'TThe identity function The input value. The same value. id 12 // Evaluates to 12 id "abc" // Evaluates to "abc"
normalizedName: Policy<unit,RegistrationError,string,string>compose: Policy<'env,'error,'input,'middle> -> Policy<'env,'error,'middle,'output> -> 'env -> 'input -> Result<'output,'error>Composes two policies left to right.
requireName: Policy<unit,RegistrationError,string,string>" Ada " |> Flow.verify normalizedName |> Flow.run () |> shouldEqual (Exit.Success "Ada")
" " |> Flow.verify normalizedName |> Flow.run () |> shouldEqual (Exit.Failure(Cause.Fail NameRequired))
(|>): '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.Flowverify: Policy<'env,'error,'input,'output> -> 'input -> Flow<'env,'error,'output>Creates a flow that verifies an input with an environment-aware policy. When the Flow runs, verify supplies its current environment to the policy. An Ok result succeeds with the policy output. An Error result short-circuits the workflow through its typed error channel. The reusable verification rule to apply. The input value to verify. A cold flow that succeeds or fails with the policy result.
normalizedName: Policy<unit,RegistrationError,string,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
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.
NameRequiredBoth policies must use the same environment and error types. The first policy's output type must match the second policy's input type.
Policy.pass returns its input unchanged. Use it when a composition requires a policy but no verification is needed.
Enable a policy from the environment
Use Policy.optional enabled policy when the environment decides whether a policy applies:
let orderLimit =
withinLimit
|> Policy.optional _.EnforceLimit
orderLimit: Policy<AppEnv,OrderError,int,int>withinLimit: Policy<AppEnv,OrderError,int,int>(|>): '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.PolicyModuleConstructors and combinators for environment-aware workflow requirements.
optional: ('env -> bool) -> Policy<'env,'error,'input,'input> -> 'env -> 'input -> Result<'input,'error>Runs a policy only when the environment predicate is true; otherwise returns the input unchanged.
_arg1: AppEnvEnforceLimit: bool9 |> Flow.verify orderLimit |> Flow.run { EnforceLimit = false; Limit = 5 } |> shouldEqual (Exit.Success 9)
9 |> Flow.verify orderLimit |> Flow.run { EnforceLimit = true; Limit = 5 } |> shouldEqual (Exit.Failure(Cause.Fail TooLarge))
(|>): '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.Flowverify: Policy<'env,'error,'input,'output> -> 'input -> Flow<'env,'error,'output>Creates a flow that verifies an input with an environment-aware policy. When the Flow runs, verify supplies its current environment to the policy. An Ok result succeeds with the policy output. An Error result short-circuits the workflow through its typed error channel. The reusable verification rule to apply. The input value to verify. A cold flow that succeeds or fails with the policy result.
orderLimit: Policy<AppEnv,OrderError,int,int>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
EnforceLimit: boolLimit: intshouldEqual: '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.
TooLargeWhen enabled env is true, the policy runs. When it is false, the policy returns the input unchanged. For this
reason, Policy.optional requires the policy's input and output types to be the same.
Choose between Policy and Bind
Use Policy when a verification rule has a domain name, appears in multiple workflows, reads the environment,
composes with other rules, or can be enabled by configuration.
Use Bind when one let!, do!, or return! site only needs to assign or map the error
of its source. Bind produces a computation-expression marker; a policy is a reusable function that Flow.verify
runs as a workflow step.

