Repository F# setup
open Reified
open Reified.Refinements
open Reified.ResultWorking with collections
Applying a fallible operation to every item produces a list of results. traverse and sequence turn that into one
result holding every value.
open System
open Reified.Result
type SignupError =
| AgeMissing
| AgeNotANumber of string
| AgeOutOfRange of int
let parseAge (raw: string) =
Int32.TryParse raw
|> Result.fromTry
|> Result.orError (AgeNotANumber raw)
|> Result.bind (fun age ->
if age >= 0 && age < 130 then Ok age else Error (AgeOutOfRange age))
SystemReifiedResultFsLiveDocsGeneratedPage14_F2D257DD2F93.SignupErrorAgeMissingAgeNotANumberstringAn abbreviation for the CLI type . Basic Types
AgeOutOfRangeintAn abbreviation for the CLI type . Basic Types
parseAge: string -> Result<int,SignupError>raw: stringSystem.Int32Represents a 32-bit signed integer.
TryParse: string * byref<int> -> boolConverts the string representation of a number to its 32-bit signed integer equivalent. A return value indicates whether the conversion succeeded. A string containing a number to convert. When this method returns, contains the 32-bit signed integer value equivalent of the number contained in , if the conversion succeeded, or zero if the conversion failed. The conversion fails if the parameter is or , is not of the correct format, or represents a number less than Int32.MinValue or greater than Int32.MaxValue. This parameter is passed uninitialized; any value originally supplied in will be overwritten. if was converted successfully; otherwise, .
(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
fromTry: bool * 'value -> Result<'value,unit>Converts a .NET Try* tuple into a unit-error result.
orError: 'error -> Result<'value,'discardedError> -> Result<'value,'error>Replaces whatever error a result carries with the supplied typed error. Ok passes through unchanged. The natural follow-up to okIf/failIf, which fail with unit precisely so the reason is chosen here: value |> Result.okIf isValid |> Result.orError MyError. Use Result.mapError instead when the existing error carries something worth keeping, as a Violation does.
bind: ('a -> Result<'b,'c>) -> Result<'a,'c> -> Result<'b,'c>Binds a result to the next fail-fast operation.
age: int(>=): 'T -> 'T -> boolStructural greater-than-or-equal The first parameter. The second parameter. The result of the comparison. 5 >= 1 // Evaluates to true 5 >= 5 // Evaluates to true [1; 5] >= [1; 6] // Evaluates to false
(&&): bool -> bool -> boolBinary 'and'. When used as a binary operator the right hand value is evaluated only on demand The first value. The second value. The result of the operation.
(<): 'T -> 'T -> boolStructural less-than comparison The first parameter. The second parameter. The result of the comparison. 1 < 5 // Evaluates to true 5 < 5 // Evaluates to false (1, "a") < (1, "z") // 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.
traverse
traverse maps each item with a Result-returning function and collects the successes.
[ "1"; "2"; "3" ] |> Result.traverse parseAge
// Ok [1; 2; 3]
[ "1"; "abc"; "500" ] |> Result.traverse parseAge
// Error (AgeNotANumber "abc")
(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
traverse: ('input -> Result<'output,'error>) -> 'input seq -> Result<'output list,'error>Maps each value with a result-returning function, stopping at the first error. Takes any sequence and always produces a list. Traversal stops at the first error, so later mappings do not run. Use one of the accumulating builders when every error should be reported. [ "1"; "2" ] |> Result.traverse parseInt // Ok [ 1; 2 ]
parseAge: string -> Result<int,SignupError>sequence
sequence is the same operation when you already hold the results, it is traverse id.
[ Ok 1; Ok 2 ] |> Result.sequence
// Ok [1; 2]
[ Ok 1; Error AgeMissing; Ok 3 ] |> Result.sequence
// Error AgeMissing
OkRepresents an OK or a Successful result. The code succeeded with a value of 'T.
(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
sequence: Result<'value,'error> seq -> Result<'value list,'error>Turns a sequence of results into one fail-fast result containing all successes. Takes any sequence and always produces a list. Stops at the first error. [ Ok 1; Error "missing"; Ok 3 ] |> Result.sequence // Error "missing"
ErrorRepresents an Error or a Failure. The code failed with a value of 'TError representing what went wrong.
AgeMissingIt stops at the first error
Traversal stops mapping after the first failure. This matters when mapping performs a lookup, request, or write.
let mutable visited = []
let recordAndParse raw =
visited <- raw :: visited
parseAge raw
[ "1"; "abc"; "3" ] |> Result.traverse recordAndParse
// Error (AgeNotANumber "abc")
List.rev visited
// ["1"; "abc"]
visited: string listrecordAndParse: string -> Result<int,SignupError>raw: string(::)parseAge: string -> Result<int,SignupError>(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
traverse: ('input -> Result<'output,'error>) -> 'input seq -> Result<'output list,'error>Maps each value with a result-returning function, stopping at the first error. Takes any sequence and always produces a list. Traversal stops at the first error, so later mappings do not run. Use one of the accumulating builders when every error should be reported. [ "1"; "2" ] |> Result.traverse parseInt // Ok [ 1; 2 ]
Microsoft.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.
rev: 'T list -> 'T listReturns a new list with the elements in reverse order. The input list. The reversed list. let inputs = [ 0; 1; 2 ] inputs |> List.rev Evaluates to [ 2; 1; 0 ].
"3" was never visited. Only the first failure is reported; later items are not examined.
traverseAll and sequenceAll
Use these when every item should be tried and every failure reported:
[ "1"; "abc"; "500" ] |> Result.traverseAll parseAge
// Error [AgeNotANumber "abc"; AgeOutOfRange 500]
[ Ok 1; Error AgeMissing; Error (AgeNotANumber "x") ] |> Result.sequenceAll
// Error [AgeMissing; AgeNotANumber "x"]
(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
traverseAll: ('input -> Result<'output,'error>) -> 'input seq -> Result<'output list,'error list>Maps each value with a result-returning function, running every mapping and collecting every error. Takes any sequence and always produces a list. The sequence is enumerated once, in order, and every mapping runs even after one fails, so a mapping with side effects runs for every item. Errors appear in input order. Each mapping contributes one error; nothing is flattened. Use traverse when the first failure should stop the work. [ "1"; "x"; "y" ] |> Result.traverseAll parseInt // Error [ NotANumber "x"; NotANumber "y" ]
parseAge: string -> Result<int,SignupError>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.
AgeMissingAgeNotANumbersequenceAll: Result<'value,'error> seq -> Result<'value list,'error list>Turns a sequence of results into one result containing all successes, or every error. Takes any sequence and always produces a list. Errors appear in input order. [ Ok 1; Error "missing"; Error "invalid" ] |> Result.sequenceAll // Error [ "missing"; "invalid" ]
The rules:
- Every mapping runs, in input order, even after one has failed. If the mapping does real work, it does that work for every item.
- Errors come back in input order, one per failing item. Nothing is flattened: a mapping that itself returns
Result<_, 'error list>produces a list of lists, so map it down first if you want one flat list. - The input sequence is enumerated once, up front, so a lazy sequence is fully forced and an infinite one will not terminate.
To accumulate across differently-typed independent steps rather than across one collection, see collecting every error.
Shape in and shape out
Both take any seq<_> and produce a list. The four complete signatures are in the
Result API reference.
An array or a seq goes in; a list comes out. Convert afterwards with Result.map when you need a different shape:
[| "1"; "2" |] |> Result.traverse parseAge |> Result.map Array.ofList
// Ok [|1; 2|]
(|>): '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
Reified.Result.ResultModuleFail-fast helpers over the standard F# Result type.
traverse: ('input -> Result<'output,'error>) -> 'input seq -> Result<'output list,'error>Maps each value with a result-returning function, stopping at the first error. Takes any sequence and always produces a list. Traversal stops at the first error, so later mappings do not run. Use one of the accumulating builders when every error should be reported. [ "1"; "2" ] |> Result.traverse parseInt // Ok [ 1; 2 ]
parseAge: string -> Result<int,SignupError>map: ('a -> 'b) -> Result<'a,'c> -> Result<'b,'c>Maps the success value of a result.
Microsoft.FSharp.Collections.ArrayModuleContains operations for working with arrays. See also F# Language Guide - Arrays.
ofList: 'T list -> 'T arrayBuilds an array from the given list. The input list. The array of elements from the list. let inputs = [ 1; 2; 5 ] inputs |> Array.ofList Evaluates to [| 1; 2; 5 |].
All four convert the input to a list up front, so a lazy sequence is fully forced and an infinite one will not
terminate through any of them. traverse and sequence then stop mapping at the first failure, while
traverseAll and sequenceAll run every mapping.