I'm trying to write some function that handle errors by returning double options instead of doubles. Many of these functions call eachother, and so take double options as inputs to output other double options. The problem is, I can't do with double options what I can do with doubles--something simple like add them using '+'.
For example, a function that divides two doubles, and returns a double option with none for divide by zero error. Then another function calls the first function and adds another double option to it.
Please tell me if there is a way to do this, or if I have completely misunderstood the meaning of F# option types.
This is called lifting - you can write function to lift another function over two options:
let liftOpt f o1 o2 =
match (o1, o2) with
| (Some(v1), Some(v2)) -> Some(f v1 v2)
| _ -> None
then you can supply the function to apply e.g.:
let inline addOpt o1 o2 = liftOpt (+) o1 o2
liftA2
as mentioned above will provide a general way to 'lift' any function that works on the double
arguments to a function that can work on the double option
arguments.
However, in your case, you may have to write special functions yourself to handle the edge cases you mention
let (<+>) a b =
match (a, b) with
| (Some x, Some y) -> Some (x + y)
| (Some x, None) -> Some (x)
| (None, Some x) -> Some (x)
| (None, None) -> None
Note that liftA2
will not put the cases where you want to add None
to Some(x)
in automatically.
The liftA2
method for divide also needs some special handling, but its structure is generally what we would write ourselves
let (</>) a b =
match (a, b) with
| (Some x, Some y) when y <> 0.0d -> Some (x/y)
| _ -> None
You can use these functions like
Some(2.0) <+> Some(3.0) // will give Some(5.0)
Some(1.0) </> Some(0.0) // will give None
Also, strictly speaking, lift
is defined as a "higher order function" - something that takes a function and returns another function.
So it would look something like this:
let liftOpt2 f =
(function a b ->
match (a, b) with
| (Some (a), Some (b)) -> f a b |> Some
| _ -> None)
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