您将如何在 OCaml 中实现reverse state monad? (由于它严重依赖于惰性,所以我猜必须使用标准库中的惰性模块)。

最佳答案

我竖起了Gist of a solution

棘手的是:

type 's l = 's Lazy.t
type ('a, 's) st = 's -> ('a * 's l)

let bind (mx : ('a, 's) st) (f : ('a -> ('b, 's) st)) (s : 's l) : ('b * 's l) =
  (* conceptually we want

         let rec (lazy (y, s'')) = lazy (mx s')
             and (lazy (z, s')) = lazy (f y s)
         in (force z, s'')

     but that's not legal Caml.

     So instead we get back lazy pairs of type ('a * 's l) l and we
     lazily project out the pieces that we need.
   *)
  let rec ys'' = lazy (mx (LazyUtils.join (LazyUtils.snd zs')))
    and (zs' : ('b * 's l) l) = lazy (f (Lazy.force (LazyUtils.fst ys'')) s)
  in (Lazy.force (LazyUtils.fst zs'), LazyUtils.join (LazyUtils.snd ys''))

正如我在评论中提到的那样,有些棘手的地方是您不想过早地强制执行状态的计算。不幸的是,为了正确实现相互递归,您还不得不暂时使计算的答案(正在向前流动)变得懒惰。因此,基本的经验法则是:
  • 执行类型告诉您的操作。
  • 除非在lazy e构造下,否则从不强制执行状态。

  • 特别是,LazyUtils.join : 'a Lazy.t Lazy.t -> 'a Lazy.t不能是:
    let join xll = Lazy.force xll
    

    因为那样会迫使外部重击为时过早。相反,它必须是:
    let join xll = lazy (Lazy.force (Lazy.force xll))
    

    看起来像是断断续续,但实际上正确地延迟了所有计算。

    关于haskell - OCaml中的反向状态monad,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24943140/

    10-13 01:31