考虑以下定义。我正在使用Racket。
(define fact/k
(lambda (n k)
(cond
((zero? n) (call/cc (lambda (f) (k f))))
(else (* n (fact/k (sub1 n) k))))))
(define five (call/cc (lambda (k) (fact/k 5 k))))
现在如果按以下方式调用
(五1)
它什么都没有。完成后,如果直接调用五,它会给出120。
$五个
120
但如果我重试(5次1),则表示120不是程序。
据我所知,最初有五点指向(零?n)基本情况下的延续。但我不确定如何解释上述行为。
使用不同参数
的另一次运行$(5 4)
$ five
480
答案 0 :(得分:1)
注意:在不改变语言操作的情况下,#!racket的最新版本中不允许使用您的代码。进入语言>选择语言并取消选中“强制常量定义”。如果不加以控制,你将失去一些优化。
five
是类似于(lambda (n) (set! five (* 5 4 3 2 1 n)))
的延续,通过使用两个延续,您可以在一次调用后重新定义five
。之后评估five
会在参数为(* 5 4 3 2 1 1)
时回复1
,在(* 5 4 3 2 1 4)
时为4
。
Scheme / Racket中的变量没有类型但值有。这意味着变量five
可以首先是过程/继续,只是数秒。这就是你看到的情况。
编辑回顾一下我重命名一下:
(define fact/k
(lambda (n k)
(cond
((zero? n) (call/cc (lambda (f) (k f))))
(else (* n (fact/k (sub1 n) k))))))
(define five (call/cc (lambda (k) (fact/k 5 k)))) ; #1
five ; ==> #<continuation>, f to be precise #2
(five 4) #3
five ; ==> 480 #4
考虑标记的第1行。在fact/k
中,默认情况下运行n 5..1,因此您可以使用(define five (call/cc (lambda (five-k) (* 5 4 3 2 1 (fact/k 0 five-k)))))
替换该行。而不是fact/k
返回一个数字,它使用延续调用和它传递的值作为值fact/k
中f
的延续。
如果您随后评估#2上的five
,则会获得f
延续。使用数字参数调用f
将成为自从我们中止并返回f以来从未发生过的计算的最后一个答案。
在#3中,以{4}作为参数调用five
。延续是时间旅行所以现在回到(define five (call/cc (lambda (five-k) (* 5 4 3 2 1 (fact/k 0 five-k)))))
,您只知道(fact/k 0 five-k)
评估为4
。接下来会发生的是(* 5 4 3 2 1 4)
成为480``and that is set to
五个since setting the variable is done *after the calculation of it's value*.
On line #4 you verify that
五个'确实已经从一个延续变为一个值。它的价值被改为一种完全不同的类型。你不能拨打电话。
在 DrRacket 中,您可以点击调试按钮并逐步完成。我建议你尝试一下。