Your understanding is fundamentally correct.
There are two monads in flight here: the Result monad (
Error), and the Lwt monad that encapsulates its concurrency semantics. It’s common in Caqti to be working with results held within Lwt (i.e.
('a, 'err) Result.t Lwt.t), and so it is useful (using something like this
>>=?? helper in this example) to be able to thread binding functions down to those inner results without explicitly matching on them (just the same as you’d use Result’s
>>= on bare result values).
If you didn’t use an operator like
test example function in the sample you linked would have to look something like:
let test db =
>>= (function Ok () -> reg_bike db "BIKE-0000" "Arthur Dent" | (Error _) as err -> Lwt.return err)
>>= (function Ok () -> reg_bike db "BIKE-0001" "Ford Prefect" | (Error _) as err -> Lwt.return err)
…and so on, using the bind (
>>=) operator defined by Lwt.
In Haskell, this nested relationship (and useful composed operations around it, like what
>>=?? does) would be formalized using a monad transformer. There is a library providing such functionality in OCaml (@ivg et al.‘s excellent monads library), but such patterns aren’t commonly applied (unfortunately so IMO, but ofc, others’ opinions vary ).