我是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 *)
答案 0 :(得分:11)
继续k
是一个函数,它从evenk
获取结果并执行“其余的计算”并产生“答案”。答案的类型和“其余计算”的含义取决于您使用CPS 的。 CPS本身通常不是目的,但考虑到某些目的。例如,在CPS形式中,实现控制运算符或优化尾调用非常容易。在不知道你想要完成什么的情况下,很难回答你的问题。
对于它的价值,如果你只是想尝试从直接样式转换为延续传递样式,而你所关心的只是答案的价值,那么传递身份函数作为延续是正确的。
下一步是使用CPS实施evenk
。我会做一个更简单的例子。
如果我有直接式功能
let muladd x i n = x + i * n
如果我假设CPS原语mulk
和addk
,我可以写
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 ...