已经给出了一般性答案,但具体来说,对于cont_sumlist
,
因此,这表达了方程 ,但是评估链被明确表示为这些连续函数的链,每个函数都将其结果提供给它上面的连续函数;而不是隐含在基于堆栈的评估机制中。sumlist (h::t) = h + sumlist t
换句话说fun x -> c (h + x)
= c ∘ (h +)
,所以当我们沿着 list 前进时[h1; h2; h3; ...]
,延续被逐步构造为c0 ∘ (h1 +) ∘ (h2 +) ∘ (h3 +) ∘ ...
,并且0
当列表被完全搜索时最终被调用;c0
用户对最顶层调用的最顶层延续在哪里,例如
cont_sumlist [1,2] (fun x -> x)
=
(fun x -> (fun x -> (fun x -> x) (1 + x)) (2 + x)) 0
=
(fun x -> x)
(fun x -> (1 + x))
(fun x -> (2 + x)) 0
=
(1 + (2 + 0))
所以整体cont_sumlist [x; y; z; ... ; n] c
变成
(c ∘ (x +) ∘ (y +) ∘ (z +) ∘ ... ∘ (n +) ) 0
=
c (x + (y + (z + .... + (n + 0) .... )))
关键区别在于不涉及堆栈卷绕和展开,并且直接从右到左计算总和,以类似 C 的伪代码作为一系列简单步骤给出
r = 0;
r += n;
.......
r += z;
r += y;
r += x;
call c(r); // call c with r, without expecting c to return; like a jump
有人可能会说,整体延续的构造类似于收起堆栈,其应用类似于在传统的基于堆栈的评估下展开堆栈。
另一种说法是,CPS 定义了一种特殊的函数调用协议,与通常的类 C 协议不同,它期望每个函数调用都返回。
CPS 定义中的每种情况都可以解释为为函数提供一个小步语义转换规则:{ [] } --> 0 ; { (h::t) } --> h + { t }
.