注意:在不更改语言选项的情况下,#!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
。如果你然后评估five
#2,你会得到f
延续。使用数字参数调用f
成为计算的最后一个答案,自从我们中止它并返回 f 以来从未发生过。在 #3 中,您five
使用 4 作为参数调用。延续是时间旅行,所以你现在回到(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中,您可以点击调试按钮并单步执行。我建议你试试看。