【问题标题】:Continuation Passing Style Computation Expression继续传递样式计算表达式
【发布时间】:2019-04-08 19:37:41
【问题描述】:

你能在 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

我做错了什么?

【问题讨论】:

    标签: f# continuation-passing computation-expression


    【解决方案1】:

    问题是计算构建器中的 Delay 函数会立即调用该函数 - 这意味着当您调用 mapk 时,它将立即运行模式匹配,然后递归调用 mapk(在传递它之前Bind 操作的结果)。

    您可以通过使用 Delay 的实现来解决此问题,该实现返回一个函数,该函数仅在给出最终延续后才调用 f - 这样,递归调用将只返回一个函数(无需进行更多递归调用导致堆栈溢出):

    member this.Delay(f) = (fun k -> f () k)
    

    使用此版本的Delay,您的代码可以按预期工作。

    【讨论】:

      猜你喜欢
      • 2012-09-17
      • 1970-01-01
      • 2012-07-04
      • 1970-01-01
      • 1970-01-01
      • 2011-11-17
      • 1970-01-01
      • 1970-01-01
      • 2016-06-25
      相关资源
      最近更新 更多