Bind in ReScript (not to import JS, but to bind multiple Option or Result)

In scala, we can write the following by comprehension notation.

val result = for {
  a <- Some(1)
  b <- Some(2)
} yield a + b

In fsharp, we can use computation expressions.

let result = 
  option {
    let! a = Some 1
    let! b = Some 2
    return a + b
  }

In fp-ts, it is as follows

const result = pipe(
    O.bindTo("a")(O.some(1)),
    O.bind("b", () => O.some(2)),
    O.map(({ a, b }) => a + b)
  );
}

Can I write a similar process in rescript?
I don’t want the nesting to be too deep when chaining flatMaps.

Rescript does not have a similar specialized syntax for these types of (i.e. monadic) computations.

There are some tools to help:

  • If we’re processing a singular piece of data through multiple steps, -> can prevent the calls from nesting.
let result = 
  Some(5)
  ->Option.filter(n => n != 0)
  ->Option.flatMap(n => 10 / n)
  ->Option.map(n => n + 7)
  • If we need to combine a small number of values, a switch works nicely:
let result = 
  switch (Some(1), Some(2)) {
    | (Some(a), Some(b)) => Some(a + b)
    | (_, _) => None 
  }

There’s not a straightforward approach to building up a scope over time, though.

3 Likes

Another alternative using Array. Use this when you have a lot of values.

let a = Some(3)
let b = Some(5)
let addOptions = (acc, opt) => Some(acc->Option.getOr(0) + opt->Option.getOr(0))
let result = [a, b]->Array.reduce(None, addOptions)
2 Likes

On this note, while more specific to the option case, also worth knowing about Array.filterMap and Array.keepSome

Array.filterMap([1, 3, 5, 7], n => n > 4 ? Some(n) : None)
// [5, 7]

Array.keepSome([Some("a"), None, Some("b")])
// ["a", "b"]
2 Likes