Delimited Continuation 实现 State Monad
发表于更新于阅读时长 1 分钟可能标题看起来有点像乱码.
最近看了一篇讲 delimited continuation 的教程,不过里面的运行时比较难搞到,所以我就想能不能用最能直击函数式编程本质的 scheme 来写。结果在安装最广泛的 Guile (因为是 make 的依赖)里找到了 control 这个模组.
control 和 call/cc 相比,提供了两个原语,shift 和 reset。两者的语法分别是
scheme
reset body1 body2shift cont body1 body2
简单地说来,shift 就是获取当前直到最近的 reset 的 continuation,把它绑定到 cont 上,然后执行body.
然后来实现 get 和 set
scheme
(define (get) (shift k (λ (v) ((k v) v))))(define (set v) (shift k (λ (_) ((k v) v))))
这里比较 trick 的一点是((k v) v)
,第一个 v 是当前函数返回的值,第二个则是后续的 state.
还需要实现 run
scheme
(define (run thunk) (reset (let ([result (thunk)]) (λ (state) result))))
使用 let 让 thunk 先求值.
跑一下试试
scheme
(define (calc)(set (* (get) (get)))(+ 1 (* 10 (get))))(display ((run calc) 5))
会输出 251.
好吧,但是这有什么用? 首先,这里没有一个变量却仍然实现了可变状态,这很酷。此外,ocaml-multicore也用这个技术实现 Algebraic Effect,说不定过几年就能在普通版的 ocaml 里用上.