如何解决方案中按需调用
(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))))
我觉得我错过了一些东西,但是在call by need 中调用 foo
并将此对象作为 f
,它会计算一次 f
并且then 永远不会更新 res
和 n
。这样对吗?我错过了什么吗?
谢谢。
解决方法
你说得对。只有使用 call-by-name 时,begin
表达式才会在每次调用 f
时得到评估(第一次除外)——以找出它是什么我们正在调用,仅当确实调用了 f
。
使用call-by-value,begin
表达式将只计算一次,在第一次调用 foo
之前。
call-by-need可能最多被评估一次,如果在第一次调用 foo
结束时有一个需要再次调用 f
。
让我们看看如何在常规的 call-by-value 方案中模拟 call-by-name 版本:
(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))))
在 Racket 中调用 (fact2 5)
会产生 120
。
对于 call-by-value 语义,您的代码不需要更改(在常规的 call-by-value 方案中解释)并且当然会循环,对于(fact-2 5)
调用(在 Racket 中确实如此)。
并且在 call-by-need 语义下,每个 lambda 的主体(两个新的 lambda 包装器的)将仅在第一次被调用时进行评估,随后它将保存计算出的值然后归还;并且对于所有后续调用,将立即返回保存的值,而不评估主体。因此,set!
表单最多会被评估一次,并且带有示例测试调用 (fact-2 5)
的代码将再次循环。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。