我有这样的代码,知道参数是通过需要调用传递的:
(define fact-2
(let ((foo (lambda (n f)
(if (zero? n)
1
(f n f)))))
(lambda (n)
(let ((res 1))
(foo n (begin
(set! res (* res n))
(set! n (- n 1))
foo))
res))))我觉得我缺少了什么,但是在调用foo时,它将计算f一次,然后永远不会更新res和n。这是正确的吗?我是不是遗漏了什么?
谢谢。
发布于 2021-02-18 15:09:07
你是对的。只有通过名称调用,begin表达式才会在每次对f的调用中得到评估(第一次除外) --找出我们正在调用的是什么,只有当对f的调用确实进行时。
通过按值调用,begin表达式只会在第一次调用foo之前计算一次。
对于按需要调用,它最多可能会被评估一次,当第一次调用foo时,如果在第一次调用结束时需要再次调用f。
让我们看看如何在常规的按值调用方案中模拟按名称调用的版本:
(define fact2
(let ((foo (lambda (n f)
(if (zero? (n)) ;; (n) NB
1
((f) n f))))) ;; (f) NB
(lambda (n)
(let ((res 1))
(foo (lambda () n) ;; (lambda () ...) NB
(lambda () ;; (lambda () ...) NB
(begin
(set! res (* res n))
(set! n (- n 1))
foo)))
res))))调用(fact2 5)在球拍中生成120。
对于按值调用语义,您的代码不需要更改(在常规的逐值调用方案中进行解释),当然也不需要对(fact-2 5)调用进行循环(实际上,在Racket中也是如此)。
在按需求调用语义下,每个lambda的主体(两个新的lambda包装器)将只在第一次被调用时进行评估,因此它将保存计算的值,然后返回它;对于所有后续的调用,保存的值将立即返回,而不对主体进行评估。因此,set!表单最多会被计算一次,使用示例测试调用(fact-2 5)的代码将再次循环。
https://stackoverflow.com/questions/66214476
复制相似问题