我刚刚开始通过SICP(我自己;这不适合一个班级),我已经在练习1.6中苦苦挣扎了几天,我似乎无法弄明白.这是Alyssa重新定义if的方式cond,如下所示:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause))
Run Code Online (Sandbox Code Playgroud)
她在一些简单的情况下成功测试它,然后用它来重新编写平方根程序(它工作得很好if):
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
Run Code Online (Sandbox Code Playgroud)
然后问题是:"当Alyssa试图用它来计算平方根时会发生什么?解释." [如果有必要,我很高兴能重现其他程序(good-enough?,improve,等),只是让我知道.]
现在,我知道会发生什么:它永远不会返回一个值,这意味着程序无限地递归.我无法解释为什么会这样.无论之间存在什么微妙的差异,if并且new-if正在逃避我.任何和所有帮助非常感谢.
Gre*_*ill 77
new-if是一个功能.调用函数时,Scheme对参数列表的第一件事是什么?它评估所有参数.
小智 37
new-if是一个程序,而Scheme使用了应用顺序评估(1.1.5),因此即使在new-if实际执行之前,它也必须首先评估所有参数,即guess和(sqrt-iter (improve guess x) x).你可以看到后一个参数是一个递归,它调用一个新的new-if过程,这就是无限循环的发生方式.
普通if不必评价其论据第一,只是一路上去,这之间的区别if和new-if.:)
ale*_*asi 23
首先,您必须了解应用订单评估与正常订单之间的区别.Lisp使用了应用顺序,但条件表达式的评估与普通函数不同(sicp chapter 1.1.6):
(if <predicate> <consequent> <alternative>)
Run Code Online (Sandbox Code Playgroud)
为了评估if表达式,解释器首先评估
<predicate>表达式的一部分.如果<predicate>求值为true值,则解释器将计算<consequent>并返回其值.否则,它会计算<alternative>并返回其值.
在 Scheme 中可以通过三种方式评估表单:
f(x)=x+x:3*f(1)*f(1)⇒3*2*2f(x)=x+x:3*f(1)*f(1)⇒ 3*(1+1)*(1+1)(也用于“惰性求值”)and和or. 例如:(and <e1> ... <en>)计算左→右。如果任何计算结果为 false,则 and 表达式的值为 false,并且<e>不计算 's的其余部分。if和cond
(if <predicate> <consequent> <alternative>):如果<predicate>计算结果为真值,解释器然后计算<consequent>并返回其值。否则,它计算<alternative>并返回它的值(cond (<p1> <e1>) ... (<pn> <en>)):<p1>先评估谓词。如果其值为 false,则<pn>对其进行评估。如果<pn>的值也为假,则<pn+1>进行评估。当谓词为真时,解释器返回相应后续表达式的值<e>。对于练习 1.6:
new-if是正常程序。在 Scheme(和许多其他语言)中,在调用过程之前完全评估参数。这称为应用顺序。∴sqrt-iter每次被调用都会new-if被调用,导致无限循环。if是一种特殊形式。除非<alternative>调用 ,否则不会评估递归语句。以前的答案很棒。我将添加另一个以更彻底的方式解释的内容。
考虑这种差异的另一种方式是这样的:递归如何使用if在某个点停止,而递归如何使用new-if永远循环?
首先让我们看看这两个if是如何工作的,然后他们在这种情况下是如何工作的。
if要评估 if 表达式,解释器首先评估
<predicate>表达式的一部分。如果<predicate>计算结果为真值,解释器然后计算<consequent>并返回它的值。否则,它会评估<alternative>并返回其值。
new-if@Schmudde对此进行了解释:
在调用过程之前,所有参数都被完全评估。
if在某个点停止?它正在停止,因为在guess足够好的地方(即(good-enough? guess x)是true),我们将有:
(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
Run Code Online (Sandbox Code Playgroud)
而且,由于predicate现在是true,解释器将评估consequent(这是guess),返回它的价值和将不再评估的alternative(这是(sqrt-iter (improve guess x) x))。
所以if实际上(sqrt-iter (improve guess x) x)递归评估直到guess足够好。然后它停止递归。
new-if永远循环?与 一样if, withnew-if (sqrt-iter (improve guess x) x)将被递归评估,直到guess足够好。
但随后它会(sqrt-iter (improve guess x) x)一次又一次地继续评估。为什么?因为在评估时:
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
Run Code Online (Sandbox Code Playgroud)
由于new-if是一个过程,它不会检查是否(good-enough? guess x)为真以决定评估guess或(sqrt-iter (improve guess x))。它的作用是,它会评估(good-enough? guess x),guess并且(sqrt-iter (improve guess x)),因为这些都是过程的参数。因此,即使guess足够好,它也会继续(sqrt-iter (improve guess x))递归调用:/。