Parameters 按需致电计划

Parameters 按需致电计划,parameters,scheme,parameter-passing,anonymous-recursion,call-by-need,Parameters,Scheme,Parameter Passing,Anonymous Recursion,Call By Need,我的代码知道参数是通过按需调用传递的: 我觉得我遗漏了什么,但在按需调用foo时,该对象为f,它将计算f一次,然后将永远不会更新res和n。这是正确的吗?我错过什么了吗 谢谢。你说得对。只有通过名称调用,begin表达式才会在每次调用f时进行计算(第一次除外)——只有在确实调用了f的情况下,才能找出我们调用的是什么 通过值调用,begin表达式在第一次调用foo之前只计算一次 对于按需调用,它最多可能得到一次评估,如果在第一次调用foo结束时需要再次调用f 让我们看看如何在常规的按值调用方案中

我的代码知道参数是通过按需调用传递的:

我觉得我遗漏了什么,但在按需调用
foo
时,该对象为
f
,它将计算
f
一次,然后将永远不会更新
res
n
。这是正确的吗?我错过什么了吗


谢谢。

你说得对。只有通过名称调用,
begin
表达式才会在每次调用
f
时进行计算(第一次除外)——只有在确实调用了
f
的情况下,才能找出我们调用的是什么

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

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


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

呼叫
(fact2 5)
在球拍中产生
120

对于按值调用语义,您的代码不需要更改(将在常规的按值调用方案中进行解释),当然,对于
(fact-25)
调用,您的代码将循环(实际上,在Racket中也是如此)


在“按需调用”语义下,每个lambda的主体(两个新lambda包装器的主体)将仅在第一次调用时进行评估,然后保存计算值并返回;对于所有后续调用,将立即返回保存的值,而不计算主体。因此,
设置表单最多会被评估一次,并且代码,以及示例测试调用
(fact-25)
将再次循环。

在第一次调用
foo
之后,
foo
在无限循环中调用自身。由于
foo
只是在调用自身,因此数值参数
n
永远不会递减,因此永远不会达到零来终止循环。根据我的老师,你错了,它应该在(开始…)中不断更新n但我不明白为什么,因为在callby need中,只要添加一点输出,就可以很容易地显示出来。在
foo
中添加一行,如
(显示“输入foo:n:”)(显示n)(换行符)
,作为第一行。然后调用
(事实2-5)
。您将看到一个无休止的输出流,其中使用参数4调用
foo
。@clataq--callby need是一个懒惰的计算模型,Scheme急切地计算函数调用中的参数。您不能在Scheme REPL中运行此代码,以便在按需调用模型下对其行为进行推理。您能解释更多吗?我只看到
fact-2
使用参数
n
foo
调用
foo
。而
foo
只调用带有参数
n
foo
foo
。没有任何地方可以减少
foo
减量
n
。我没有看到任何关于懒惰的记忆或其他机制被建立起来。@clartaq具体解释什么?我的回答中有三种说法。你是在问需要打电话吗?具体来说,您的问题是什么?是的,关于“按需调用”(或任何其他参数传递约定)。如果没有可见的方法阻止
foo
递归,我就看不出任何对
fact-2
的调用如何能够成功。否则,我将重复O.P.s.的问题。“我遗漏了什么吗?”谢谢你的坚持。@clartaq我已经编辑了答案。:)在“按值调用”下,操作代码不需要更改,当然会循环,对于
(fact-25)
调用。@adabsurdum“…将出现非终止循环。”是的,就是这样。我的意思是,我们必须做一些修改,以表示OP代码的按名称调用解释,以在Racket的按值调用系统中运行的代码来表示;所以,不需要任何更改来通过值解释来表示其调用,因为Racket已经是这样了。
(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))))
(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))))