首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >按需呼叫计划

按需呼叫计划
EN

Stack Overflow用户
提问于 2021-02-15 19:47:19
回答 1查看 94关注 0票数 1

我有这样的代码,知道参数是通过需要调用传递的:

代码语言:javascript
复制
(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一次,然后永远不会更新resn。这是正确的吗?我是不是遗漏了什么?

谢谢。

EN

回答 1

Stack Overflow用户

发布于 2021-02-18 15:09:07

你是对的。只有通过名称调用,begin表达式才会在每次对f的调用中得到评估(第一次除外) --找出我们正在调用的是什么,只有当对f的调用确实进行时。

通过按值调用,begin表达式只会在第一次调用foo之前计算一次。

对于按需要调用,它最多可能会被评估一次,当第一次调用foo时,如果在第一次调用结束时需要再次调用f

让我们看看如何在常规的按值调用方案中模拟按名称调用的版本:

代码语言:javascript
复制
(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)的代码将再次循环。

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66214476

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档