【问题标题】:Common Lisp - flatting a list that may contain symbolsCommon Lisp - 扁平化可能包含符号的列表
【发布时间】:2012-05-25 04:29:01
【问题描述】:

这是99 Lisp problems 中的第 7 个:通过将每个列表替换为其元素(递归),将列表(可能将列表作为元素保存)转换为“平面”列表。我尝试了几种解决方案,例如来自#2680864from here。它们都可以工作,但是如果我正在展平包含引用元素的列表,我会遇到问题。例如:

> '(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……它们的行为方式都相同。

【问题讨论】:

  • 您遇到的问题是由于 LISP 读取表达式时引号符号 (') 转换为 (quote ...) 的事实。为了更容易阅读输出,当 LISP 打印您的列表时会发生相应的转换。因此,让 LISP 将其读取为列表时,无法区分两者。

标签: list common-lisp quote flatten


【解决方案1】:

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

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

在 Common Lisp 中,' 是一个将 'a 扩展为 (QUOTE A) 的 readmacro。由于这是一个普通列表,典型的展平操作会将符号QUOTEA 收集到展平列表中。这是因为 flatten 函数通常会检查某物是否是原子。如果您不希望这样,您的 flatten 函数需要检查某个元素是原子还是以QUOTE 作为其第一个符号的二元素列表。

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

例如:

(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))

【讨论】:

  • (defun flatten (l) (cond ((null l) nil) ((atom l) (list l)) ((equal l (list 'QUOTE (second l))) (cdr l)) (t (loop for a in l appending (flatten a))))) 这给了我(A B C)。如果我有(flatten '(A 'B C)),我想没有办法获得(A 'B C),我无法控制传递给展平的列表。我认为这解决了我的问题,虽然有一点不对称:)
  • @Antonio Bonifati:查看添加的示例
猜你喜欢
  • 1970-01-01
  • 2022-01-17
  • 2019-11-29
  • 2011-05-12
  • 2014-11-10
  • 2012-04-02
  • 2019-09-28
  • 1970-01-01
相关资源
最近更新 更多