您可以使用F#中的计算表达式来实现CPS吗?
Brian McNamara's blog提供了以下解决方案:
type ContinuationBuilder() =
member this.Return(x) = (fun k -> k x)
member this.ReturnFrom(x) = x
member this.Bind(m,f) = (fun k -> m (fun a -> f a k))
member this.Delay(f) = f()
let cps = ContinuationBuilder()
看起来不错。我可以在CPS中编写List.map
:
let rec mapk f xs = cps {
match xs with
| [] -> return []
| x::xs ->
let! xs = mapk f xs
return f x::xs
}
但是它会溢出:
mapk ((+) 1) [1..1000000] id
我在做什么错了?
答案 0 :(得分:6)
问题是您在计算生成器中的Delay
函数将立即调用该函数-这意味着当您调用mapk
时,它将立即运行模式匹配,然后调用{{1} }(在将结果传递到mapk
操作之前)。
您可以通过使用Bind
的实现来解决此问题,该实现返回仅在得到最终延续后才调用Delay
的函数-这样,递归调用将仅返回一个函数(没有进行更多的递归调用导致堆栈溢出):
f
使用此版本的member this.Delay(f) = (fun k -> f () k)
,您的代码可以正常工作。