我正在努力平整树木结构。我通过将每个原子符号与树中的其余部分进行比较来递归地进行,但我的一位朋友提出了以下代码,我认为这些代码看起来更清晰。我只是不理解这一行:
((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)))))
如果有人可以节省时间,那么解释会很棒吗?谢谢!
答案 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 explained,flatten
应该始终返回一个列表,这样可以确保(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
p
和r
,并从s
返回s
的值。如果cond
产生错误,则尝试a
,依此类推。
b
基本上是一个广义的cond
,您可以使用额外的括号付费:尝试这种情况,或其他尝试该情况等等。