不。这个callcc
的实现不依赖懒惰评估。为了证明这一点,我将以严格的功能语言来实现它,并且显示k n
之后的任何内容都不会被执行。
我将使用的严格的函数式语言是JavaScript。由于JavaScript不是静态类型的,因此不需要声明newtype
。因此,我们首先在JavaScript中定义Cont
monad的return
和>>=
函数。我们将分别调用这些函数unit
和bind
:
function unit(a) {
return function (k) {
return k(a);
};
}
function bind(m, k) {
return function (c) {
return m(function (a) {
return k(a)(c);
});
};
}
接下来我们定义callcc
如下:
function callcc(f) {
return function (c) {
return f(function (a) {
return function() {
return c(a);
};
})(c);
};
}
现在,我们可以定义quux
如下:
var quux = callcc(function (k) {
var n = 5;
return bind(k(n), function() {
alert("Hello World!");
return unit(25);
});
});
注意,我在bind
的第二个参数内添加一个alert
来测试它是否被执行。现在,如果您拨打quux(alert)
,它将显示5
,但它不会显示"Hello World!"
。这证明bind
的第二个参数从未执行过。您自己请参阅demo。
为什么会发生这种情况?我们从quux(alert)
开始。通过测试减少它等同于:
(function (k) {
var n = 5;
return bind(k(n), function() {
alert("Hello World!");
return unit(25);
});
})(function (a) {
return function() {
alert(a);
};
})(alert);
通过测试再次减少它,它变成了:
bind(function() {
alert(5);
}, function() {
alert("Hello World!");
return unit(25);
})(alert);
通过公测减少bind
下一步,我们得到:
(function (c) {
return (function() {
alert(5);
})(function (a) {
return (function() {
alert("Hello World!");
return unit(25);
})(a)(c);
});
})(alert);
现在我们可以看到为什么"Hello World!"
从未显示。通过beta测试,我们正在执行function() { alert(5); }
。这个函数的作用是调用它的参数,但它从来没有这样做。由于这种执行停止,并且从不显示"Hello World!"
。总之:
该callcc
功能不依赖于懒惰的评价。 k
被称为不是因为懒惰的评价,但因为没有调用它的第一个参数,因此立即返回调用k
断链后
通过callcc
创建函数结束。
这让我回到你的问题:
而且我们可以从k
定义是\a -> cont $ \_ -> h a
,在上面我们已经\x -> runCont ((\_ -> return 25) x) c
被传递到与下划线忽略的参数看。最终,return 25
被有效地“忽略”,因为从未使用下划线参数,因此懒惰评估从未评估过。
你错了。正如你所看到的k
是(\a -> cont $ \_ -> h a)
,函数(\x -> runCont ((\_ -> return 25) x) c)
被传递给被k
忽略的参数。在那之前你是正确的。然而,这并不意味着return 25
由于懒惰评估而未被评估。它根本不被评估,因为从未调用函数(\x -> runCont ((\_ -> return 25) x) c)
。我希望把事情弄清楚。
在某些语言的Scheme中,它被实现为primop – jozefg