Recently I discovered a style of programming which is very useful (and pretty) in functional world called Railway oriented programming. For example when want to create a pipeline of functions that produce option type, and we want to return None if any of them fails we can do something like this:
someOptionValue // : 'a option
>>= func1 // func1: 'a -> 'b option
>>= func2 // func2: 'b -> 'c option
and so on...
where (>>=) : 'a option -> (a' -> 'b option) -> 'b option
operator applies a value to the left hands side if it's Some value
or None
otherwise.
But, here is my problem, what if we have a function that "takes" two (or many) option types, let say funcAB : 'a -> 'b -> 'c option
, valA : 'a option
and valB : 'b option
and we still want to create this pipeline or use some nice operator (not create a new one specifically for this, but use some standard approach, in particular I don't want to use match ... with
to "unpack" option values)
Currently I have something like this:
valA
>>= (funcAB >> Some)
>>= (fun ctr -> valB >>= ctr)
But is doesn't seem 'correct' (or fun is the better word ;] ), and it doesn't scale well if a function takes more parameters or we want to create a longer pipeline. Is there a better way to do this?
I've used F# syntax but I think this question can be applied to any functional programming language, like OCaml and Haskell.
EDIT (Solution):
Thanks to the chi's answer I've created following code F# which is much more idiomatic then what I previously had:
funcAB <!> valA <*> valB |> Option.flatten
And it looks well if we have more values: funcAB <!> valA <*> valB <*> valC <*> ...
.
I've used operators defined in YoLo.
In Haskell, we can use Applicative
syntax for that:
If
valA :: f a
valB :: f b
funAB :: a -> b -> f c
then
join $ funAB <$> valA <*> valB :: f c
provided f
is a monad (like Maybe
, Haskell's option
).
It should be adaptable to F# as well, I guess, as long as you define your operators
(<$>) :: (a -> b) -> f a -> f b
(<*>) :: f (a -> b) -> f a -> f b
join :: f (f a) -> f a
The above trick is a poor man's version of Idris !-notation (bang notation).
Another common option is using do
do a <- valA
b <- valB
funAB a b
but this is comparable with using >>=
, indeed:
valA >>= \a ->
valB >>= \b ->
funAB a b
is not much more complex.
One option is to use computation expressions. For option
there is no standard one but you can easily create your own:
type OptionBuilder() =
member this.Bind (x, f) = Option.bind f x
member this.Return x = Some x
let optional = OptionBuilder()
let a, b = Some(42), Some(7)
let f x y = x + y
let res = optional {
let! x = a
let! y = b
return f x y
}
which closely resembles Haskells do
notation.
For more advanced features, have a look at F#+ which also has a generic applicative functor operator <*>
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With