【问题标题】:Rewrite f# functions with continuation-passing style用延续传递风格重写 f# 函数
【发布时间】:2014-09-21 20:40:56
【问题描述】:

这个问题是关于函数式编程的。示例代码在 F# 中。

假设我有一个简单的函数 f:

let f x = 
    x + 1

现在(出于我不想解释的原因,与线程有关)我必须将 f 转换为具有延续的函数:

let f x cont =
    cont (x+1)

现在我必须重写所有调用 f 的函数,这将不再编译。

例如,如果我有这个功能

let g x =
   let res = f x
   res + 2

我必须将 g 重写为

let g x cont =
    f x (fun res ->
            cont (res + 2) )

这已经变得复杂了,但仍然可以解决。

但问题是:我该如何重写下面这段代码?

let lmapped = [ for x in l do
                    let res = f x
                    yield res + 1 ]
if List.isEmpty lmapped then
   ...

有没有简单的方法来重写它? (可能避免显式递归函数,例如“let rec ...”)谢谢

【问题讨论】:

    标签: f# functional-programming ocaml


    【解决方案1】:

    使用显式延续传递样式编写代码很快就会变得丑陋。

    在这种情况下,您需要编写List.map 函数的基于延续的版本:

    let map f list cont = 
      let rec loop acc list cont = 
        match list with
        | [] -> cont (List.rev acc) // Reverse the list at the end & call continuation!
        | x::xs -> f x (fun x' ->   // Call `f` with `cont` that recursively calls `loop`
            loop (x'::acc) xs cont )// Call `loop` with newly projected element in `acc`
      loop [] list cont
    

    原则上,这只是一个“简单的句法转换”,可以“自动”完成,但要做到这一点而不迷路是非常困难的!

    该函数实际上只是一个普通的map 函数,它带有内部loop 函数,它递归地遍历输入列表并调用f 进行投影。除了所有函数都采用附加参数cont并在最后调用cont返回结果。传递给 map 的 f 函数也是如此!见:

    map (fun n cont -> cont (n * 2)) [1 .. 10] (printfn "%A")
    

    如果您大量使用延续,那么编写计算构建器(又名 monad)来处理延续可能会更容易。这不太适合单个 StackOverflow 答案,但请参阅此 excellent post by Brian McNamara

    【讨论】:

      【解决方案2】:

      所以用 Tomas 的 map 函数来回答这个问题:

      先将代码改写为

      let lmapped = List.map
                     (fun x ->
                         let res = f x
                         res + 1 )
                     l
      if List.isEmpty lmapped then
        ...
      

      然后我们可以用延续重写:

      map
         (fun x cont ->
               f x (fun res ->
                       cont (res + 1 )))
         l
         (fun lmapped ->
              if List.isEmpty lmapped then
      
                   ... 
              )
      

      【讨论】:

        猜你喜欢
        • 2012-04-19
        • 1970-01-01
        • 2011-12-16
        • 1970-01-01
        • 2011-06-30
        • 2010-12-21
        • 1970-01-01
        • 1970-01-01
        • 2012-12-12
        相关资源
        最近更新 更多