时髦的通话/ cc使用。它是如何工作的?

时间:2014-12-12 23:17:43

标签: lambda scheme racket callcc

考虑以下定义。我正在使用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

1 个答案:

答案 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/kf的延续。 如果您随后评估#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 中,您可以点击调试按钮并逐步完成。我建议你尝试一下。

相关问题