As it was already suggested, you can use monad transformers, to compose several monads into a single monad. As a show-case, we will use the monads library (disclaimer, I am an author of this library), which you can install with

```
opam install monads
```

It offers most of the well-known monads in a form of a monad transformer, which in terms of OCaml, is a functor that takes a monad and returns a new monad that enriches it with some new behavior. For example, to make a non-deterministic error monad, we can do `Monad.List.Make(Monad.Result.Error)`

and get a monadic structure (i.e., a module that implements the Monad.S interface) that is both a list monad and an error monad. The small caveat is that the operations of the wrapped monad, the error monad in our case, are not available directly, so we have to *lift* them, e.g.,

```
let fail p = lift @@ Monad.Result.Error.fail p
```

So that in the end, the full implementation of the transformed monad still requires some boilerplate code,

```
module ListE = struct
type 'a t = 'a list Monad.Result.Error.t
include Monad.List.Make(Monad.Result.Error)
let fail p = lift@@Monad.Result.Error.fail p
(* and so on for each operation that is specific to the wrapped monad *)
end
```

Now, let’s try wrapping the Lwt monad into the state. We don’t want to add the Error monad because Lwt is already the error monad and adding an extra layer of errors monad is not what we want. First of all, we need to adapt the `Lwt`

monad to the `Monad.S`

interface, e.g.,

```
module LwtM = struct
type 'a t = 'a Lwt.t
include Monad.Make(struct
type 'a t = 'a Lwt.t
let return = Lwt.return
let bind = Lwt.bind
let map x ~f = Lwt.map f x
let map = `Custom map
end)
end
```

If we want to keep the state type monomorphic, then we will need a module for it. Suppose your state is represented as,

```
module State = struct
type t = string Map.M(String).t
end
```

Now, we can use it to build our `State(Lwt)`

Russian doll,

```
module IO = struct
include Monad.State.T1(State)(LwtM)
include Monad.State.Make(State)(LwtM)
(* let's lift [read] as an example *)
let read fd buf ofs len =
lift (Lwt_unix.read fd buf ofs len)
end
```

The `Monad.State.T1`

functor is used to create the types for the generated monad. You can write them manually, of course, like as we did in the List(Error) example, but the type generating modules are here for the convenience^{1}

Now, let’s get back to the problem of the lifting. It looks tedious to impossible to lift every operation from Lwt. Commonly, we try to put the smaller monad inside, to minimize the work, but it doesn’t work with Lwt as the latter is not a transformer. So what is the solution? For me, the solution is to not lift the operations at all, but instead, define your IO abstraction and hide that it is using Lwt underneath the hood. This will make the code that uses this new abstraction more generic and less error-prone so that it can focus on the business logic and the implementation details could be hidden inside the monad implementation. This is what the monads are for, anyway.

^{1)} We omit the types from the output of the `Make`

functor since for a long time OCaml didn’t allow the repetition of types in a structure so having the types in it will prevent us from composing various flavors of monads using `include`

. It is also a long-time convention widely used in many OCaml libraries, including Core and Async. A convention that we probably don’t need anymore.