1

考虑以下定义。我正在使用球拍。

(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))))

现在如果它调用如下

(五一)

它什么也没有。这样做后,如果直接调用 5,它会给出 120。

五美元

120

但是如果我重试(5 1)它会失败,说 120 不是程序。

我知道最初有五个点指向在(零?n)基本情况下捕获的延续。但我不确定如何解释上述行为。

另一个使用不同参数的运行

$(五四)

五美元

480

4

1 回答 1

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。如果你然后评估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 tosince setting the variable is done *after the calculation of it's value*. On line #4 you verify that五`确实已经从一个延续变成了一个值。它的值更改为完全不同的类型之一。你不能拨打一个号码。

DrRacket中,您可以点击调试按钮并单步执行。我建议你试试看。

于 2014-12-13T00:18:36.367 回答