Description
I like using Option. I'm wondering if the module should be filled out with some functions that are available in Option packages from other languages. Most of these functions are simple conveniences that aren't strictly necessary. But they lead to shorter and sometimes easier-to-understand code. If we provide conversion functions from both sides, like option->null and null->option, the programmer finds it more easily. Maybe standardize on terminology for lazy forms. These usually take just a few lines to implement. What do you think? Should we consider augmenting the Option module? Similar changes could be made to Result as well. I've looked at F# and fp-ts. Here are some ideas. If there is interest in this, I can do more research and make a proposal.
module type Ideas = {
let valueExn: option<'a> => 'a // same as getExn
let valueUnsafe: option<'a> => 'a
let valueOrDefault: (option<'a>, 'a) => 'a
let valueOrDefaultWith: (option<'a>, unit => 'a) => 'a // new lazy form
let concat: (option<'a>, option<'a>, ('a, 'a) => 'a) => option<'a>
let orElseWith: (option<'a>, unit => option<'a>) => option<'a> // lazy form
let map2: (option<'a>, option<'b>, ('a, 'b) => 'c) => option<'c>
let map3: (option<'a>, option<'b>, option<'c>, ('a, 'b, 'c) => 'd) => option<'d>
let fold: (option<'a>, 'b, ('a, 'b) => 'b) => 'b
let match: (option<'a>, 'b, 'a => 'b) => 'b // same as mapWithDefault?
let matchWith: (option<'a>, unit => 'b, 'a => 'b) => 'b
let iter: (option<'a>, 'a => unit) => unit
let exists: (option<'a>, 'a) => bool
let contains: (option<'a>, 'a) => bool
let count: option<'a> => int
let flatten: option<option<'a>> => option<'a>
let toArray: option<'a> => array<'a>
let toList: option<'a> => list<'a>
let toUndefined: option<'a> => Js.undefined<'a>
let toNull: option<'a> => Js.null<'a>
let fromUndefined: Js.undefined<'a> => option<'a>
let fromNull: Js.null<'a> => option<'a>
let fromPredicate: ('a, 'a => bool) => option<'a>
}
module Option = {
let fromPredicate = (a, pred) => a->Some->Option.filter(pred)
let concat = (a, b, f) => {
switch (a, b) {
| (a, None) => a
| (None, b) => b
| (Some(a), Some(b)) => Some(f(a, b))
}
}
let fold = (i, j, f) => {
switch i {
| None => j
| Some(i) => f(i, j)
}
}
}
module Examples = {
let nums = [Some(5), None, Some(9)]
let sum1 = nums->Array.reduce(0, (sum, next) => next->Option.fold(sum, (i, j) => i + j))
let sum2 = nums->Array.reduce(None, (sum, next) => sum->Option.concat(next, (i, j) => i + j))
let s2 = (s: string) =>
s
->String.trim
->String.concat("abc")
->String.replace("a", "x")
->Option.fromPredicate(i => String.length(i) <= 50)
}