Lambda Funky call/cc用法。它是如何工作的?
考虑以下定义。我在用球拍Lambda Funky call/cc用法。它是如何工作的?,lambda,scheme,racket,callcc,Lambda,Scheme,Racket,Callcc,考虑以下定义。我在用球拍 (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 但是如
(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不是一个过程
据我所知,最初在(0?n)基本情况下捕获的连续性有五个点。但我不确定如何解释上述行为
使用不同参数运行另一次
元(五元四角)
五美元
480NB:在最新版本的#中不允许使用您的代码!不改变语言操作的球拍。进入语言>选择语言并取消选中“强制常量定义”。您将失去一些未经检查的优化
five
是一个类似于(lambda(n)(set!five(*5 4 3 2 1 n))
的延续,通过使用两个延续,您可以在一次调用后重新定义five
。当参数为1
时,对5
进行评估,然后查看(*54321)
的答案;当参数为4
时,对(*543214)
进行评估
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
(定义事实/k
(λ(北k)
(续)
((零分)(呼叫/抄送(lambda(f)(kf)))
(其他(*n(事实/k(子1 n)k()())))
(定义五个(call/cc(lambda(k)(fact/k5k)))#1.
五个;==>#,f准确地说是#2
(五个4)#3
五个;==>480 #4
考虑到标记线#1。在fact/k
中,默认情况下为n5..1运行,因此您可以用替换该行(定义五(call/cc(lambda(五-k)(*54321(fact/k0five-k)'))
)。它使用continuation调用返回一个数字,而不是fact/k
,它作为值传递的是fact/k
调用的f
中的continuation。
如果然后在#2上计算five
,则得到f
继续。使用数值参数调用f
将成为计算的最后一个答案,因为我们中止了计算并返回了f。
在#3中调用five
,4作为参数。延续是一种时间旅行,所以现在您可以回到(定义五(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``并且设置为
5,因为变量的设置是在计算其值*之后*完成的。
在第4行,您确认
five`确实已从一个continue更改为一个value。它的值被更改为一个完全不同的类型。你不能打电话
在DrRacket中,您可以点击debug按钮并单步执行。我建议你试试看 我想我快拿到了。但为什么五是反弹到乘法?这是否与继续的开始是函数的返回这一事实有关?(来自事实/k基本情况)。可能是我缺少了一些关于call/cc如何工作的概念性知识来理解这一点。@chamibuddhika我已经更新了我的答案。这是因为调用continuation就像跳入代码。
five
的绑定是k
和f