public class Result<T> {
public bool HasError { get; set; }
public T Value { get; set; }
public string Error { get; set; }
}
type Either<'a, 'b> =
| Left of 'a
| Right of 'b
type Result<'T,'TError> =
| Ok of ResultValue:'T
| Error of ErrorValue:'TError
let construction value =
match System.Int32.TryParse(value) with
| (true, int) -> Ok int
| _ -> sprintf "Could not parse value %s" value |> Error
API is string -> Result<int, string>
let pipeline value =
value
|> parseInt
|> Result.bind (fun x ->
if x > 10 then
Ok x
else
Error "Value must be greater than 10"
)
|> Result.map (fun x -> x * 2)
|> Result.mapError (fun error -> sprintf "Error: %s" error)
API is string -> Result<int, string>
Result<a', 'error> -> a' -> 'b -> Result<'b, 'error> is the API
Takes a mapping function and invokes if Ok
Result<a', 'error> -> a' -> Result<'b, 'error> -> Result<'b, 'error>
is the API
If the value is Ok invokes a construction function.
Result<a', 'error> -> 'error-> 'errorResult -> Result<'a, 'errorResult>
is the API
If the value is Error invokes a mapping function.
let consumption value =
match value |> pipeline with
| Ok ok -> ok
| Error error -> failwith error
Using pattern matching to deconstruct the result similar to any other union.