为什么我的lisp函数会给我这个输出?

时间:2017-02-19 00:58:16

标签: list lisp common-lisp

我正在编写一个将从用户那里获取列表的函数,并将此列表展平为一个简化列表。该函数似乎只返回列表中的第一项而不是其余项?关于它为什么这样做的任何建议?

示例:

> (flatten '(a () b (c d))
(a b c d)

这是我到目前为止所拥有的

(defun flatten (list)
(cond 
    ((null list)t) 
        (list (first list) (rest list))
        (t(append (flatten (first list))
                (flatten (rest list)))
    (t(cons (first list (flatten (rest list))))))))

它给出的输出

> (flatten '(a () b (c d)))
(NIL B (C D))

1 个答案:

答案 0 :(得分:3)

您正在使用更新的代码编辑原始问题,这使其成为移动目标。目前,在我要求Emacs用 M-q (lisp-mode)缩进它之后,你的代码如下:

(defun flatten (list)
  (cond 
    ((null list)t) 
    (list (first list) (rest list))
    (t (append (flatten (first list))
               (flatten (rest list)))
       (t (cons (first list (flatten (rest list))))))))
;;  ^^^ Something is not good, why is the clause indented?  

括号构造计算机的代码,而缩进是为人类读者打印此结构的一种方法。这种冗余允许您在源代码与另一个不匹配时检测问题。这里,(t cons)不是cond子句,它嵌套在前一个子句中。

其次,如评论中所述,cond将转到测试成功的第一个子句。如果你写了(cond (t X) ...)...部分中的任何内容都不会改变代码的含义,代码总是返回X。在您的代码中,您按如下方式进行测试:

  1. (null list)测试listeq还是nil
  2. list 测试list是否为列表。有一个名为listp的谓词可以检测到它。当你单独放置list时,你会问list是否是一个广义的真值,当你之前排除nil(前一个句子)时,这个值必然是正确的。
  3. 默认条款(t ...)无法使用,因为之前的测试不会失败。
  4. 这是一个骨架:

    (defun flatten (form)
      (cond
        ((null list) ...)
        ((consp list) ...)
        (t ...)))
    

    而不是consp您可以编写listp,但请注意,根据定义,列表可以是nil或cons小区,因此consp更加明确,与nil的测试不重叠。还要注意,我总是测试表单的类型,这是一种经常找到的模式。这就是为什么你可能更喜欢使用typecase