I'm getting myself familiar with monad transformers in OCaml using monads library.
Here is an example I'm working with:
open Base
open Stdio
open Monads.Std
module St = struct
include Monad.State.T1 (Monoid.Int) (Monad.Ident)
include Monad.State.Make (Monoid.Int) (Monad.Ident)
end
module W = Monad.Writer.Make (Monoid.String) (St)
let w_example =
let open W in
let writer =
let* () = write "A" in
let* () = lift (St.put 42) in
return (-1)
in
let w_result = run writer in
let s_result, state = St.run w_result 0 in
s_result, state
let () = printf "((%d, %s), %d)\n" (fst (fst w_example)) (snd (fst w_example)) (snd w_example)
I have two questions:
-1
, the log A
, and the state 42
all at once without manually run
-ing all the composed monads inwards?put
a new state into W
monad, I needed to separate St
module in order to expose St.put
. W
does not have put
exposed. Is there a way if I just went withmodule W =
Monad.Writer.Make
(Monoid.String)
(struct
include Monad.State.T1 (Monoid.Int) (Monad.Ident)
include Monad.State.Make (Monoid.Int) (Monad.Ident)
end)
without a separate St
?
run
function that goes through all the layer of the monad stack:let run x st = St.run (W.run x) st
It is also a good place to define a more human-friendly return type like
type 'a t = { int_st : int; string_st : string; return : 'a }
let run x st =
let ((return, string_st), int_st) = St.run (W.run x) st in
{ int_st; string_st; return }
Monad.State.Make (Monoid.Int) (Monad.Ident)
before using its put
function anyway. Trying to avoid naming the St
monad would be mostly unpractical.