I am working on understanding Railway Oriented Programming (Scott Wlaschin style) in F#. In my example I want to create a pipeline which does some calculation, applies two different functions to the output of that initial calculation, then hands off a tuple of its results to a final function.
In real code the 'initial calculation' might be getting some data, the 'two different functions' might produce a textual summary and a chart of the data, and the final function might be rendering some output containing both the text and the chart.
I've invented a bind2
function to achieve this, but I can't help thinking that if this was a good idea it would already be common practice and must appear (in disguise) in existing libraries such as Scott's.
Please let me know how I would achieve what I want in an idiomatic style.
Here's my code. All above bind2
is taken broadly from Scott's code, the remainder is my bind2
function and a simple demo.
type Result<'S, 'F> =
| Success of 'S
| Failure of message : 'F list
let bind f x =
match x with
| Success s -> f s
| Failure f -> Failure f
let bind2 (f1 : 'A -> Result<'B, 'F>)
(f2 : 'A -> Result<'C, 'F>) (x : Result<'A, 'F>) : Result<'B * 'C, 'F> =
match x with
| Success _ ->
let r1, r2 = (bind f1) x, (bind f2) x
match r1, r2 with
| Success s1, Success s2 ->
Success(s1, s2)
| Failure f1, _ ->
Failure f1
| _, Failure f2 ->
Failure f2
| Failure f -> Failure f
let demo1 (a: int) : Result<int, string> =
Success a
let demo2 (a: int) : Result<string, string> =
a |> string |> Success
let demo3 (a: int) : Result<string, string> =
a |> (*) -1 |> string |> Success
let demo4 (s1 : string, s2 : string) =
sprintf "%s - %s" s1 s2 |> Success
let Demo =
bind demo1
>> bind2 demo2 demo3
>> bind demo4