Indeed, you can notice a common pattern for the shape of such functions like `List.map_result`

that work with different types. And this pattern is usually called `traverse`

:

```
val traverse : ('a -> 'b option) -> 'a list -> ('b list) option
val traverse : ('a -> ('b, 'e) result) -> 'a list -> ('b list, 'e) result
val traverse : ('a -> 'b Lwt.t) -> 'a list -> ('b list) Lwt.t
val traverse : ('a -> 'b option) -> 'a array-> ('b array) option
val traverse : ('a -> ('b, 'e) result) -> 'a array-> ('b array, 'e) result
val traverse : ('a -> 'b Lwt.t) -> 'a array-> ('b array) Lwt.t
(* and so on ... *)
```

You can see that implementing every single monomorphic function will result in a total of **O(N x M)** implementations which is quite a lot of boilerplate to write and maintain if you ask me.

Good news! It’s possible to implement a single implementation of `traverse`

per a collection type if the function result type implements the following module signature known as **Applicative**:

```
module type Applicative = sig
type 'a t
val pure : 'a -> 'a t
val both : 'a t -> 'b t -> ('a, 'b) t
end
```

(and types like `option`

, `result`

, `Lwt.t`

and many others can trivially implement this).

Once you have this, you can generalise `traverse`

, and its implementation will give you `map_result`

and `fold_result`

for free. So in some sense, it’s a nice modular abstraction that gives you quite a lot of flexibility.

As for the question about collecting errors, this is already happen to be solved as mentioned by @xvw. You can have the following type usually known as `validation`

:

```
type ('a, 'e) validation =
| Failure of 'e
| Success of 'a
```

And the `Applicative`

implementation for `validation`

combines errors instead of returning the first one. Thus, `traverse`

over a list collects all errors instead of short-circuiting on the first one. I think it’s a nice design because you don’t have the make a choice for an end user (users usually don’t like this), and you give more flexibility while allowing for extensibility.

However, whether it’ll be convenient enough to work with these `Applicative`

and `Traverse`

modules instead of monomorphic functions is a separate question