I'm looking through the F# docs and am wondering about a "missing" function in the Option module. There is a map2
that takes two options and seems to do a logical AND
on it. If either is None, the result is None. Otherwise if you've got a Some(a) and Some(b), it returns a Some(f(a,b)).
Where is the logical OR
function? I would expect a similar function where if just one is Some, return it. But if both are Some, it would do the Some(f(a,b)) like for the logical AND case. I can write this out manually no problem with a pattern matching.
let concat f a b =
match a, b with
| Some(a), Some(b) -> Some(f a b)
| Some(a), None -> Some(a)
| None, Some(b) -> Some(b)
| _ -> None
Practically this could be useful if you've got a list of optional numbers and you want to add them up. The answer is None if the list is empty or only contains None values. None doesn't affect the result, like a zero. Or a couple optional strings and you want to concatenate them.
I'm assuming since F# doesn't seem to have this function in the standard library, I must be thinking about things the wrong way. Or is there a more concise way of doing it?
What you are looking for would be a function of the following type (Note that the type is different than that of map2
because the two options provided as argument need to have the same type (so that you can return one or the other when the other one is not available):
('a -> 'a -> 'a) -> 'a option -> 'a option -> 'a option
As far as I can see, this does not exist in the standard F# library, but it sounds like a potentially useful function. For example, this exists in Haskell as unionWith
(see unionWith in the reducers package) - though, of course, in a more generalized form.
I think it is a very reasonable idea to add an implementation of this to your "utils" library or suggest an addition to the F# core libraries. I would also implement this using match
as you did. Although it is perhaps interesting that you can also get this behaviour using map2
and orElse
(which is, I think, less readable and probably slower):
let unionWith f a b =
Option.map2 f a b |> Option.orElse a |> Option.orElse b
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