Ocaml延续传球风格

时间:2010-06-18 20:45:57

标签: recursion ocaml continuation-passing

我是ocaml的新手并尝试编写一个继续传递样式函数但很困惑我需要传递给k上的附加参数的值

例如,我可以编写一个递归函数,如果列表的所有元素都是偶数,则返回true,否则返回false。

所以就像

let rec even list = .... 

在CPS上,我知道我需要添加一个参数来传递函数

let rec evenk list k = .... 

但我不知道如何处理这个k以及这是如何工作的

例如对于这个偶数函数,环境看起来像

val evenk : int list -> (bool -> ’a) -> ’a = <fun>

evenk [4; 2; 12; 5; 6] (fun x -> x)  (* output should give false *)

4 个答案:

答案 0 :(得分:11)

继续k是一个函数,它从evenk获取结果并执行“其余的计算”并产生“答案”。答案的类型和“其余计算”的含义取决于您使用CPS 。 CPS本身通常不是目的,但考虑到某些目的。例如,在CPS形式中,实现控制运算符或优化尾调用非常容易。在不知道你想要完成什么的情况下,很难回答你的问题。

对于它的价值,如果你只是想尝试从直接样式转换为延续传递样式,而你所关心的只是答案的价值,那么传递身份函数作为延续是正确的。

下一步是使用CPS实施evenk。我会做一个更简单的例子。 如果我有直接式功能

let muladd x i n = x + i * n

如果我假设CPS原语mulkaddk,我可以写

let muladdk x i n k =
  let k' product = addk x product k in
  mulk i n k'

你会看到mulptiplication首先完成,然后“继续”使用k',其执行添加,最后continues使用k,返回到muladdk呼叫者,召集者。关键的想法是,在k'的主体内,我分配了一个新的延续evenk,它代表乘法 - 加法函数中的中间点。要使{{1}}工作,您必须至少分配一个此类延续。

我希望这会有所帮助。

答案 1 :(得分:7)

每当我玩CPS时,传递给延续的东西就是你通常会回到调用者身上的东西。在这个简单的例子中,一个很好的“直觉润滑剂”就是将继续命名为“返回”。

let rec even list return =
  if List.length list = 0
    then return true
    else if List.hd list mod 2 = 1
      then return false
      else even (List.tl list) return;;

let id = fun x -> x;;

用法示例:“偶数[2; 4; 6; 8] id ;;”。

答案 2 :(得分:5)

由于您调用evenk是正确的(使用标识函数 - 有效地将延续传递样式转换回正常样式),我认为难以定义evenk。< / p> Norman说,

k是表示剩余计算并产生最终值的延续函数。因此,您需要做的是计算v even的结果,并将结果传递给k,返回k v而不仅仅是v。< / p>

答案 3 :(得分:1)

您希望将函数的结果作为输入,就好像它不是用连续传递样式编写的那样。

这是你的函数,它测试列表是否只有整数:

(* val even_list : int list -> bool *)
let even_list input = List.for_all (fun x -> x mod 2=0) input

现在让我们用延续cont

来编写它
(* val evenk : int list -> (bool -> 'a) -> 'a *)
let evenk input cont =
  let result = even_list input in
  (cont result)

您计算函数的结果,并将result传递给continuation ...