Common Lisp - 展平可能包含符号的列表

时间:2012-05-17 15:08:41

标签: list common-lisp quote flatten

这是99 Lisp problems中的#7:通过将每个列表替换为其元素(递归地),将列表转换为“平面”列表,从而将列表转换为元素。我尝试了几种解决方案,例如来自#2680864from here。它们都有效,但如果我展平包含带引号的元素的列表,我会遇到问题。 E.g:

> '(a 'b c)
(A 'B C)

> '(a (quote b) c)
(A 'B C)

> (flatten '(a 'b c))
(A QUOTE B C)

在后一种情况下,我想得到:

(A 'B C)

似乎'内部表示'妨碍了这项任务! SBCL,CLISP,ECL,......他们都表现得一样。

1 个答案:

答案 0 :(得分:2)

列表中的引用元素?这通常没有意义。你为什么要引用它?

(a b c)是三个符号的列表。为什么要引用列表中的元素?在(a 'b c)中?为什么?报价的目的是什么?

在Common Lisp中'是一个readmacro,它将'a扩展为(QUOTE A)。由于这是一个普通列表,因此典型的展平操作会将符号QUOTEA收集到平面列表中。这是因为平坦函数典型地检查某事物是否是原子。如果您不想要这个,那么您的展平函数需要检查某个东西是原子还是两个元素列表,并以QUOTE作为其第一个符号。

但正如我上面所说,默认用法只是为了展平符号,因为引号在列表中通常没用。否则你需要扩展展平功能。

例如:

(defun flatten (l &key (test #'atom))
  (cond ((null l) nil)
        ((funcall test l) (list l))
        (t (loop for a in l nconc (flatten a :test test)))))


CL-USER > (flatten '(a (('b) c) ('d) )
                   :test (lambda (item)
                           (or (atom item)
                               (and (eq (first item) 'quote)
                                    (null (cddr item))))))

(A (QUOTE B) C (QUOTE D))