2014-12-12 16 views
1

请考虑以下定义。我正在使用Racket。时髦的通话/ cc的使用。它是如何工作的?

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

它给了什么。做完,如果五是直接调用它给120

$ 5

但是,如果我重试(5 1)它没有说120不是一个程序。

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

不同参数的另一个运行

$(有五个4)

$ 5

回答

1

注意:你的代码是不允许的#的最后一个版本的球拍不改变语言操作。进入语言>选择语言并取消选中“强制常量定义”。你会放松一些优化机智这个未经检查。

five是类似于(lambda (n) (set! five (* 5 4 3 2 1 n)))的延续,通过使用两个继续,您可以在一次调用后重新定义five。之后评估five当和(* 5 4 3 2 1 4)为时回复(* 5 4 3 2 1 1)的答案。

计划/球拍中的变量没有类型,但值有。这意味着变量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 tosince setting the variable is done *after the calculation of it's value*. On line #4 you verify that五`确实已从延续更改为值。它的价值被改变成完全不同的类型之一。你不能拨打电话号码。

DrRacket你可以按调试按钮,并通过它。我建议你试试看。

+0

想想我差点拿到了。但为什么五个反弹增殖?这是否与延续的开始是从函数返回的事实有关? (从事实/ k基本情况)。可能是我错过了一些关于call/cc如何理解的概念性知识。 – chamibuddhika 2014-12-13 13:39:04

+0

@chamibuddhika我已经更新了我的答案。这是因为调用延续将会跳转到代码中。 'five'的绑定是'k'和'​​f'的延续的一部分 – Sylwester 2014-12-13 14:39:57

相关问题