在Lisp中展平树结构

时间:2013-11-22 11:36:51

标签: list recursion tree lisp

我正在努力平整树木结构。我通过将每个原子符号与树中的其余部分进行比较来递归地进行,但我的一位朋友提出了以下代码,我认为这些代码看起来更清晰。我只是不理解这一行:

((atom tree)(list tree))

我理解他们每个人单独做什么,我也知道下面的循环会有一个列表或者它会导致错误,我怀疑它有很多因为我们将符号变成列表的原因返回true。但我仍然不觉得我完全理解代码。

(defun flatten (tree)
(cond ((null tree)
     nil
     )
    ((atom tree)(list tree))
    (t
     (loop for a in tree appending (flatten a)))))

如果有人可以节省时间,那么解释会很棒吗?谢谢!

3 个答案:

答案 0 :(得分:2)

代码的格式很差。在你的问题的第一部分,它并不清楚为什么

((atom tree) (list tree))

将出现在任何 Common Lisp代码中,因为它看起来像是尝试调用(atom tree),获取函数,并使用(list tree)调用该函数。在上下文中,通过适当的格式化,它更清晰:

(defun flatten (tree)
  (cond 
   ((null tree) nil)
   ((atom tree)(list tree))
   (t (loop for a in tree
            appending (flatten a)))))

这是cond中的一个子句。它说如果 tree是一个原子(可能是一个符号,一个数字,一个向量等,其他任何不是cons的东西),那么返回(list tree)。作为larsmans explainedflatten应该始终返回一个列表,这样可以确保(flatten 3)返回(3)。由于(loop for a in tree ...)适用于列表中的任何tree,因此(null tree) 一个列表。该定义可简化为:

nil/()

Stack Overflow上有一些类似的问题,有些问题与你发布的内容几乎完全相同(以格式化模式)。这位朋友是否基于其中一个建议。无论如何,为了完整起见,您可以查看:

答案 1 :(得分:1)

  

我也知道下面的循环会占用一个列表,或者它会导致错误,我怀疑它有很多因为我们在符号返回true时将符号转换为列表的原因。

点亮。 flatten的后置条件是它的结果总是一个平面列表(不是“平面列表或原子”),因此递归调用只需要处理一种数据类型。

答案 2 :(得分:0)

((atom tree)(list tree))是一段语法,无法单独理解。它属于cond语法:它在Lisp文化中称为 cond对。 cond对表示如果(atom tree)表达式为真,则评估(list tree)cond然后终止并返回该值。

cond pair 术语是不精确的,因为在Common Lisp中,cond子句是n-ary。他们不必成对。其他表单可以完全省略,因此子句是单例项,允许cond像[{1}}一样使用:

or

此处评估(cond (a) (b) (c) ...) <==> (or a b c) 。如果它产生true(非零值),则a停止并返回cond的值。否则它会测试a等等。这正是b的作用。

可以有两种或更多种形式:

or

如果(cond (a p r s) (b t u) (c x y) ...) 结果为真,则评估a pr,并从s返回s的值。如果cond产生错误,则尝试a,依此类推。

b基本上是一个广义的cond,您可以使用额外的括号付费:尝试这种情况,其他尝试该情况等等。