【问题标题】:Remove superfluous else from cond statement?从 cond 语句中删除多余的 else ?
【发布时间】:2012-09-23 17:21:26
【问题描述】:

我目前正在阅读《小阴谋家》的第 4 版。一个早期的练习是创建一个函数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)))))))

它们是等价的吗?

【问题讨论】:

  • 我相信没有人会在其中一个搜索引擎中搜索你的标题(以下功能是否等效)......你不能改进它吗?
  • 是的,我认为你是对的。我把它改成了希望更好的东西,不过你可以随意改变它。
  • 不知何故,来自 gdoron 的提示给了他的成果:我现在正在阅读 The Little Schemer 并寻找注意到同样事情的人:) 但是,正如其他人所说,在第 41 页作者似乎鼓励这种简化。

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


【解决方案1】:

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

【讨论】:

  • 实际上我所指的示例在第 47 页,在他们展示了如何进行一些简化之后。我也一直在等待他们简化这个示例,但他们从未这样做过。
【解决方案2】:

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

本书之所以有两个conds,是因为它们服务于两个不同的目的。外部cond 区分列表数据类型的两种情况(列表是nullcons,其第二个参数是列表)。外部cond 由所使用的数据类型决定;列表上的所有结构递归函数都将具有外部cond。内部cond 特定于正在定义的特定函数。

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

【讨论】:

    【解决方案3】:

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

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

    这是我想让你想象的:现在是晚上 11:52,我很累,我的眼睛很痛,我正在阅读由学生撰写的超过 45 个针对同一问题的解决方案。我正在寻找清晰度,该死的。如果你能写出你的解决方案,让你清楚自己做对了,我会 100% 给你并祝福你的名字。

    【讨论】:

    • 我知道你从哪里来,但是我年纪越大越喜欢简洁,我阅读的代码越少,我就越容易理解函数的作用。但这是一个见仁见智的问题。
    【解决方案4】:

    它们是,是的,虽然我发现你的更容易阅读。 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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-15
      • 1970-01-01
      相关资源
      最近更新 更多