我正在编写一个将从用户那里获取列表的函数,并将此列表展平为一个简化列表。该函数似乎只返回列表中的第一项而不是其余项?关于它为什么这样做的任何建议?
示例:
> (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))
答案 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
。在您的代码中,您按如下方式进行测试:
(null list)
测试list
是eq
还是nil
。list
不测试list
是否为列表。有一个名为listp
的谓词可以检测到它。当你单独放置list
时,你会问list
是否是一个广义的真值,当你之前排除nil
(前一个句子)时,这个值必然是正确的。(t ...)
无法使用,因为之前的测试不会失败。这是一个骨架:
(defun flatten (form)
(cond
((null list) ...)
((consp list) ...)
(t ...)))
而不是consp
您可以编写listp
,但请注意,根据定义,列表可以是nil
或cons小区,因此consp
更加明确,与nil
的测试不重叠。还要注意,我总是测试表单的类型,这是一种经常找到的模式。这就是为什么你可能更喜欢使用typecase
。