Search code examples
filteringoption-typereasonbucklescript

How to flatten a list of options


I have this piece of code now:

 results
 |> List.filter(Belt.Option.isSome)
 |> List.map(item =>
      switch (item) {
      | Some(item) => item
      }
    )

Can anyone make it shorter? It is a filter that removes the non-valid values followed by a map that converts/unwraps the optional values to just values.

In Scala it would just be flatten:

scala> List(Some("test"),None,None,Some("foo"),Some("bar"),None).flatten
res4: List[String] = List(test, foo, bar)

Solution

  • flatten in Scala seems to work on any kind of monad. And this kind of polymorphism, called ad-hoc polymorphism, unfortunately isn't supported in OCaml (although it's on the roadmap, asa feature called "modular implicits"). Therefore we have to write code specific for lists of options. Using just Belt, we can do this:

    [Some("test"), None, None, Some("foo"), Some("bar"), None]
    |> Belt.List.keepMap(_, x => x)
    

    keepMap is what is called filterMap in saner standard libraries, and takes a function that should return an option instead of a bool where a None will be filtered out and Some(x) will be flattened and included in the final list as just x.