微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

方案中按需调用

如何解决方案中按需调用

我有这段代码知道参数是使用调用传递的:

(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 永远不会更新 resn。这样对吗?我错过了什么吗?

谢谢。

解决方法

你说得对。只有使用 call-by-name 时,begin 表达式才会在每次调用 f 时得到评估(第一次除外)——以找出它是什么我们正在调用,仅当确实调用了 f

使用call-by-valuebegin 表达式将只计算一次,在第一次调用 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 举报,一经查实,本站将立刻删除。