Repository F# setup
open Reified
open Reified.Refinements
open Reified.ResultQuickstart
Reified.Result is a standalone leaf. Nothing else in Reified is required, and it depends on no other Reified package:
dotnet add package Reified.Result
open Reified.Result
open Reified.ResultDSL
ReifiedResultReified.ResultDSLThe concise result vocabulary: the result { } computation expression, its accumulating result.list { } / result.array { } variants, and the lightweight admission functions (okIf, failIf, require, orError, mapError). Optional and opt-in, in the same shape as Reified.DataDSL, Reified.ConstraintDSL, and Reified.SchemaDSL: open Reified.Result for Result, then open Reified.ResultDSL for this vocabulary. Deliberately small: generic combinators such as map, bind, orElse, tap, and the traversal helpers stay qualified as Result.map, Result.bind, and so on.
The package works with the standard F# Result<'value, 'error> without wrapping or replacing it. It provides:
| Concern | API | Returns |
|---|---|---|
Turn a TryParse tuple into a Result, then name the error |
Result.fromTry, then Result.orError |
Result<'value,'error> |
| Compose dependent failures | result { } |
Result<'value,'error> |
| Collect independent failures | result.list { } with and! |
Result<'value,'error list> |
| Apply a fallible operation across a sequence | Result.traverse, Result.sequence |
Result<'value list,'error> |
| Observe without changing the value | Result.tap, Result.tapError |
Result<'value,'error> |
Compose dependent steps
open System
type QuantityError =
| InvalidInteger of string
| NotPositive of int
let quantity (raw: string) =
result {
let! parsed =
Int32.TryParse raw
|> Result.fromTry
|> Result.orError (InvalidInteger raw)
let! positive =
if parsed > 0 then Ok parsed else Error (NotPositive parsed)
return positive
}
SystemFsLiveDocsGeneratedPage9_F2D257DD2F93.QuantityErrorInvalidIntegerstringAn abbreviation for the CLI type . Basic Types
NotPositiveintAn abbreviation for the CLI type . Basic Types
quantity: string -> Result<int,QuantityError>raw: stringresult: ResultBuilderThe fail-fast result { } computation expression.
parsed: intSystem.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.
positive: int(>): 'T -> 'T -> boolStructural greater-than The first parameter. The second parameter. The result of the comparison. 5 > 1 // Evaluates to true 5 > 5 // Evaluates to false (1, "a") > (1, "z") // Evaluates to false
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.
Each failure maps to the application error type at its bind site.
Collect independent failures
let! fails fast; and! accumulates. The choice depends on the binding syntax:
result.list {
let! name = parseName input.Name
and! age = parseAge input.Age
return name, age
}
// Error [ NameMissing; AgeNotANumber "x" ]Everything inside one and! group is accumulated into a list. A later let! binds sequentially and fails fast, because
it can depend on the earlier results. See Collecting every error for the exact boundary.
Where the other packages fit
This accumulation is flat: a list of your error values with no field identity and no path. Admitting values in the first place belongs to Constraints, while path-aware accumulated diagnostics over a whole structured input belong to Reified.Schema.
All of them return the standard F# Result, so these helpers work on their output, but none of them requires this
package.