我刚刚开始通过SICP工作(我自己;这不适合上课),而且我已经在练习1.6中苦苦挣扎了几天,我似乎无法想象它出。这是Alyssa用if
重新定义cond
的地方,如下所示:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause))
她在一些简单的案例中成功测试了它,然后用它来重新编写平方根程序(它与if
配合得很好):
(define (sqrt-iter guess x)
(new-if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
然后问题是:“当Alyssa试图用它来计算平方根时会发生什么?解释。” [如有必要,我很乐意重现其他程序(good-enough?
,improve
等),请告诉我。]
现在,我知道会发生什么:它永远不会返回一个值,这意味着程序无限地递归。我无法解释为什么会这样。 if
和new-if
之间存在的微妙差异正在躲避我。任何和所有的帮助非常感谢。
答案 0 :(得分:72)
new-if
是一个功能。调用函数时,Scheme对参数列表的第一件事是什么?它评估所有参数。
答案 1 :(得分:32)
new-if
是一个过程,Scheme使用应用顺序评估(1.1.5),所以即使在实际执行new-if
之前,它也必须首先评估所有参数,即{{ 1}}和guess
。你可以看到后一个参数是一个递归,它调用一个新的(sqrt-iter (improve guess x) x)
过程,这就是无限循环的发生方式。
普通的new-if
不需要先评估其参数,只是一路走来,这是if
和if
之间的区别。 :)
答案 2 :(得分:22)
首先,您必须在申请订单评估和正常订单之间understand the difference。 Lisp使用应用顺序,但条件表达式的评估与普通函数(sicp chapter 1.1.6):
不同(if <predicate> <consequent> <alternative>)
要评估if表达式,解释器首先评估表达式的
<predicate>
部分。如果<predicate>
求值为真值,则解释器将评估<consequent>
并返回其值。否则,它会评估<alternative>
并返回其值。
答案 3 :(得分:6)
在Scheme中可以通过三种方式评估表单:
f(x)=x+x
:3*f(1)*f(1)
⇒3*2*2
f(x)=x+x
:3*f(1)*f(1)
⇒3*(1+1)*(1+1)
(也用于“惰性评估”)and
和or
。例如:(and <e1> ... <en>)
计算左→右。如果任何值的计算结果为false,则and表达式的值为false,其余<e>
的值均不计算。if
和cond
之类的条件
(if <predicate> <consequent> <alternative>)
:如果<predicate>
计算为真值,则解释器将计算<consequent>
并返回其值。否则,它将评估<alternative>
并返回其值(cond (<p1> <e1>) ... (<pn> <en>))
:谓词<p1>
首先被评估。如果其值为false,则评估<pn>
。如果<pn>
的值也为false,那么将评估<pn+1>
。当为真谓词时,解释器将返回相应结果表达式<e>
的值。对于练习1.6:
new-if
是正常过程。在Scheme(和许多其他语言)中,对参数进行充分评估,然后调用该过程。这称为应用顺序。 every每次调用sqrt-iter
时都会调用new-if
,从而导致无限循环。if
是特殊形式。除非调用<alternative>
,否则不会评估递归语句。 答案 4 :(得分:3)
以前的答案很棒。我将再添加一个更详尽的解释。
考虑这种差异的另一种方法是:使用$ docker start <container_id>
进行递归如何在某个时刻停止,而使用if
进行递归的永远循环?
首先让我们看一下这两个 if 的总体工作原理,然后看看在这种情况下它们如何工作。
new-if
这由@alex-vasi解释:
要评估if表达式,解释器将从评估表达式的
if
部分开始。如果<predicate>
评估为真值,则解释器将评估<predicate>
并返回其值。否则,它将评估<consequent>
并返回其值。
<alternative>
这由@Schmudde解释:
在调用该过程之前,将对所有参数进行充分评估。
new-if
进行的递归如何在某个时刻停止?它之所以停止,是因为在if
足够好(即guess
是(good-enough? guess x)
)的时候,我们将拥有:
true
并且由于(if (good-enough? guess x)
guess
(sqrt-iter (improve guess x)
x)))
现在为predicate
,解释器将评估true
(即consequent
),返回其值,而将不再评估 guess
(即alternative
)。
因此,(sqrt-iter (improve guess x) x)
实际上会递归计算if
,直到(sqrt-iter (improve guess x) x)
足够好为止。然后,它将停止递归。
guess
循环进行递归?与new-if
一样,对于if
new-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)))
是一个过程,所以它不会检查new-if
是否为真,以便决定评估(good-enough? guess x)
或guess
。它将执行的操作是计算(sqrt-iter (improve guess x))
,(good-enough? guess x)
和guess
,因为这些是过程的参数。因此,即使(sqrt-iter (improve guess x))
足够好,它也会继续递归调用guess
:/。
答案 5 :(得分:0)
Ex1.6。 new-if:
(define (new-if predicate then-clause else-clause)
(cond (predicate then-clause)
(else else-clause)))
与“ if陈述”的区别: if陈述式从谓词->结果->替代项
一一评估但是,“ new-if”必须评估所有参数,也就是称为MOMENT的参数(这意味着“ else-clause”在开始时就被评估!!),
因此,当这些参数中的任何一个将其自身称为迭代循环时,这将导致无限循环