SICP中练习1.6的解释是什么?


70

我刚刚开始通过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我难以理解。任何和所有帮助非常感谢。


2
“递归”的动词形式是“递归”,因此它是“递归”。
Greg Hewgill

还要与4.25进行比较:community.schemewiki.org/?
sicp

Answers:


91

new-if是一个功能。调用函数时,Scheme对参数列表做的第一件事是什么?它评估所有参数。


1
OP在Haskell中不会出现此问题!(他还会遇到其他问题……)
davidbak

45

new-if是一个过程,Scheme使用应用顺序评估(1.1.5),因此即使在new-if实际执行之前,它也必须先评估所有参数,分别是guess(sqrt-iter (improve guess x) x)。您可以看到后面的参数是一个递归,它调用一个新new-if过程,这就是无限循环的发生方式。

普通if不必评价其论据第一,只是一路上去,这之间的区别ifnew-if。:)


1
new-if过程有三个参数:predicatethen-clauseelse-clause。所以,当new-if被调用时,(good-enough? guess x)guess,并(sqrt-iter (improve guess x))进行评估。是对的吗 ?这不会改变结果,因为仅评估sqrt-iter会引起麻烦。但是imo你忘了一个争论……
Benjamin Crouzier 2015年

25

首先,您必须了解应用订单评估和正常订单之间的区别。Lisp使用应用顺序,但是条件表达式的求值方式不同于正常函数(sicp第1.1.6章):

(if <predicate> <consequent> <alternative>)

为了评估if表达式,解释器首先评估<predicate>表达式的一部分。如果<predicate>评估结果为真值,则解释器评估<consequent>并返回其值。否则,它将评估<alternative>并返回其值。


1
多谢您提供书籍参考连结。该链接被打破,但这应该工作mitpress.mit.edu/sites/default/files/sicp/full-text/book/...
抽象类

7

在Scheme中可以通过三种方式评估表单:

  1. 适用命令
    • 计算参数,然后套用
    • 给定f(x)=x+x3*f(1)*f(1)3*2*2
  2. 正常订单
    • 完全展开然后减小
    • 给定f(x)=x+x3*f(1)*f(1)3*(1+1)*(1+1)(也用于“惰性评估”中)
  3. 特殊形式,例如:
    • 布尔值andor。例如:(and <e1> ... <en>)计算左→右。如果任何值的计算结果为false,则and表达式的值为false,其余的<e>则不计算。
    • 条件和ifcond
      • (if <predicate> <consequent> <alternative>):如果<predicate>计算结果为真值,则解释器将对计算<consequent>并返回其值。否则,将评估<alternative>并返回其值
      • (cond (<p1> <e1>) ... (<pn> <en>)):谓词<p1>首先被评估。如果其值为false,则<pn>进行评估。如果<pn>的值也为false,则<pn+1>进行评估。当谓词为true时,解释器返回相应结果表达式的值<e>

对于练习1.6:

  • new-if是正常过程。在Scheme(和许多其他语言)中,在调用过程之前会对参数进行全面评估。这称为应用命令。∴sqrt-iter被称为每次new-if被调用时,导致一个无限循环。
  • 对于读者而言,normalif是一种特殊形式。除非<alternative>调用,否则不会评估递归语句。

4

以前的答案很棒。我将再添加一个更详尽的解释。

考虑这种差异的另一种方式是这样的:如何if在某个时刻停止使用递归,而在new-if永远使用循环进行递归呢?

首先,让我们看一下这两个if的总体工作原理,然后看看在这种情况下它们如何工作。

if

这由@ alex-vasi解释:

为了评估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)))

而且,由于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)))

既然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))递归调用:/。


0

示例1.6。新如果:

(define (new-if predicate then-clause else-clause)
     (cond (predicate then-clause)
                (else else-clause)))

与“ if语句”的区别:if语句从谓词->结果->替代项一一评估,

但是,“ new-if”必须评估所有参数,也就是其调用的MOMENT参数(这意味着“ else-clause”在开始时就被评估!),

因此,当这些参数中的任何一个调用自身进入迭代循环时,这将导致无限循环

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.