You may know of the newish function List.partition_map
with the following type:
List.partition_map : ('a -> ('b, 'c) Either.t) -> 'a list -> 'b list * 'c list
If you tell partition_map
how to map an 'a
to either a 'b
or a 'c
, it will partition a list of 'a
into a list of 'b
and a list of 'c
.
puzzle: write a “n-ary” version of partition_map
that supports splitting a value into N possible variants of different types, and returns a product of N different lists.
My solution lets you write the following, for example:
(* map a string to either an int, or a bool, or just the same string *)
let classify str =
match int_of_string str with
| n -> Ok n
| exception _ -> Error (
match bool_of_string str with
| b -> Ok b
| exception _ -> Error str
)
(* split a list three ways based on this *)
let test =
partition_split (Cons (Cons One)) classify
["foo"; "42"; "true"; "bar"; "0"; "false"]
The result of evaluating test
is
val test : int list * (bool list * string list) =
([42; 0], ([true; false], ["foo"; "bar"]))
(Solutions may use a different type to describe the splitting choices, and to group the partitioned lists. The point is that the choice happens between an arbitrary number of possibilities, possibly of different types, so the result of the splitting function looks like a sum 'b + 'c + 'd + ...
.)