OCaml Monad Transformers使用疑问:结果提取与状态操作
针对BAP Monads库的两个技术问题解答
问题1:一次性获取计算结果、日志和状态
可以自己封装一个顶层运行函数,将Writer和State的两层run逻辑合并,避免手动逐层调用:
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 run_writer_state (writer : 'a W.t) init_state = let state_comp = W.run writer in let (res, log), final_state = St.run state_comp init_state in res, log, final_state let w_example = let open W in let* () = write "A" in let* () = lift (St.put 42) in return (-1) let () = let res, log, state = run_writer_state w_example 0 in printf "(%d, %s, %d)\n" res log state (* 输出: (-1, A, 42) *)
这个封装函数会帮你完成两层monad的运行逻辑,直接返回三个目标值。BAP的monads库本身没有提供现成的多层run组合器,自定义顶层函数是最直接的解决方案。
问题2:内嵌State模块时的状态设置操作
无需单独定义St模块,有两种可行方案:
方案1:在W模块中封装State操作
定义W时,直接添加put、get等状态操作的封装,通过lift调用内部匿名State monad的对应方法:
module W = struct include Monad.Writer.Make (Monoid.String) (struct include Monad.State.T1 (Monoid.Int) (Monad.Ident) include Monad.State.Make (Monoid.Int) (Monad.Ident) end) (* 封装State的put操作 *) let put x = lift (Monad.State.put x) (* 可选:封装get操作 *) let get = lift Monad.State.get end let w_example = let open W in let* () = write "A" in let* () = put 42 in (* 直接调用W.put *) return (-1)
方案2:使用Monad.State.Lift模块
BAP提供的Monad.State.Lift模块可以直接在transformer上层调用下层State monad的操作,无需修改W的定义:
module W = Monad.Writer.Make (Monoid.String) (struct include Monad.State.T1 (Monoid.Int) (Monad.Ident) include Monad.State.Make (Monoid.Int) (Monad.Ident) end) let w_example = let open W in let open Monad.State.Lift (W) in (* 引入State Lift组合器 *) let* () = write "A" in let* () = put 42 in (* 直接调用Lift的put *) return (-1)
两种方案都能实现无需单独定义St模块的状态设置操作,可根据代码风格偏好选择。
内容的提问来源于stack exchange,提问作者Jay Lee
相关产品推荐
相关产品推荐

