SICP练习1.6的解释是什么?

时间:2009-07-23 11:53:14

标签: recursion sicp

我刚刚开始通过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等),请告诉我。]

现在,我知道会发生什么:它永远不会返回一个值,这意味着程序无限地递归。我无法解释为什么会这样。 ifnew-if之间存在的微妙差异正在躲避我。任何和所有的帮助非常感谢。

6 个答案:

答案 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不需要先评估其参数,只是一路走来,这是ifif之间的区别。 :)

答案 2 :(得分:22)

首先,您必须在申请订单评估和正常订单之间understand the difference。 Lisp使用应用顺序,但条件表达式的评估与普通函数(sicp chapter 1.1.6):

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

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

答案 3 :(得分:6)

在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>。当为真谓词时,解释器将返回相应结果表达式<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”在开始时就被评估!!),

因此,当这些参数中的任何一个将其自身称为迭代循环时,这将导致无限循环