我来自 OOP,非功能性背景,因此我无法完全可视化几个有关continuation pass的在线示例。此外,像 Scheme 这样的函数式语言不必指定参数类型或返回值,所以我不确定我是否正确理解了这个想法。
由于 C# 支持 lambda,我从 Wikipedia 文章中获取了第一个示例,并尝试将其移植到具有强类型的 C#,以查看该模式将如何应用:
// (Scheme)
// direct function
(define (pyth x y)
(sqrt (+ (* x x) (* y y))))
// rewriten with CPS
(define (pyth& x y k)
(*& x x (lambda (x2)
(*& y y (lambda (y2)
(+& x2 y2 (lambda (x2py2)
(sqrt& x2py2 k))))))))
// where *&, +& and sqrt& are defined to
// calculate *, + and sqrt respectively and pass the result to k
(define (*& x y k)
(k (* x y)))
因此,用 C# 重写 CPSpyth&
版本会导致:
// (C#6)
// continuation function signature
delegate double Cont(double a);
// *&, +& and sqrt& functions
static double MulCont(double a, double b, Cont k) => k(a * b);
static double AddCont(double a, double b, Cont k) => k(a + b);
static double SqrtCont(double a, Cont k) => k(Math.Sqrt(a));
// sqrt(x*x + y*y), cps style
static double PythCont(double x, double y, Cont k) =>
MulCont(x, x, x2 =>
MulCont(y, y, y2 =>
AddCont(x2, y2, x2py2 =>
SqrtCont(x2py2, k))));
我本可以使用泛型而不是double
,但签名会更长。无论如何,我不确定的是:
上面的
Cont
签名是否正确(即Func<double, double>
)?应该继续fn。接受参数,处理它,然后返回相同类型的值?当我第一次开始阅读关于延续的文章时,我觉得这个延续函数将在调用堆栈中的每个步骤中被调用,但在上面的示例中,它只传递
sqrt&
给" 原始延续的中间值。上面函数中的代码基本上类似于k(Math.Sqrt(x * x + y * y))
,那么这是否意味着我对中间“钩子”的假设是错误的?