从cond语句中删除多余的其他内容?

时间:2012-09-23 17:21:26

标签: lisp scheme conditional-statements the-little-schemer

我正在阅读第4版的“The Little Schemer”。一个早期练习是创建一个函数insertR,它在列表中的给定值的右侧插入一个值。这本书最终得出以下定义:

(define insertR
  (lambda (new old lat)
    (cond
      ((null? lat) (quote ()))
      (else (cond
              ((eq? (car lat) old)
               (cons old
                     (cons new (cdr lat))))
              (else (cons (car lat)
                          (insertR new old
                                   (cdr lat)))))))))

我自己的定义如下:

(define insertR
  (lambda (new old lat)
    (cond
      ((null? lat) (quote ()))
      ((eq? (car lat) old) (cons old (cons new (cdr lat))))
      (else (cons (car lat) (insertR new old (cdr lat)))))))

他们是等同的吗?

4 个答案:

答案 0 :(得分:3)

当然,这两个定义都是等价的,但您的定义更容易阅读。请记住,你只是在本书的第3章,作者喜欢慢慢走。在同一章的后面,在第41页,他们将精确地教你正在进行的那种简化 - 以单cond形式处理所有互斥条件,而不是嵌套cond形式

答案 1 :(得分:3)

是的,这两个定义具有相同的行为。

这本书有两个cond的原因是因为它们有两个不同的用途。外部cond区分列表数据类型的两种情况(列表是nullcons,其第二个参数是列表)。外cond由所消耗的数据类型决定;列表上的所有结构递归函数都将具有外部cond。内部cond特定于所定义的特定函数。

因此,虽然将它们组合起来更紧凑,但通过将它们分开,可以使函数的结构更清楚地与递归类型的结构相对应。如果您始终如一地使用该习惯用法,它将使您的结构递归函数更易于阅读,调试和维护。

答案 2 :(得分:3)

我要和Ryan说同样的话:可读性仅次于正确性。事实上,如果你是一名学生,可读性可能更重要比正确性重要。

本书中出现的版本的优点是它有一个双臂cond,其中一个测试空虚。这是解决问题的完全正常和预期的方法。当我看到这种分裂时,我可以迅速理解两个代码块的作用。在你的代码中,我必须停下来花时间确保这三个案例是详尽的和相互排斥的,然后推断出哪些输入属于哪个箱。

这就是我想让你想象的事情:现在是晚上11点52分,我累了,我的眼睛受伤了,我正在读四十五个解决同样问题的方法,由学生写的。我正在寻找CLARITY,并且认真。如果你能以一种明显正确的方式编写你的解决方案,那么我会给你百分之百,并祝福你的名字。

答案 3 :(得分:2)

他们是,是的,虽然我觉得你的阅读更容易。 cond支持多个子句,并对每个子句进行求值,直到其中一个求值为true。因此,以下内容:

(else (cond
        ((eq? (car lat) old) (cons old (cons new (cdr lat))))
        (else (cons (car lat) (insertR new old (cdr lat)))))))))

相当于将第二个cond的第一个子句移动到第一个子句:

(cond
  ((null? lat) (quote ()))
  ((eq? (car lat) old) (cons old (cons new (cdr lat))))
  (else (cons (car lat) (insertR new old (cdr lat)))))))

也许这本书的作者认为将终端null条件与其他两个条件分开是更清楚的,但如果是这种情况,那么if就足以代替cond }。