我想了解Clojure通过Clojure列表(或其他集合类型)表示的树或列表进行递归的习惯方式。Clojure通过集合递归的习惯方式
我可以写下面的计算在平面集合中的元素(忽视的事实是它不是尾递归):
(defn length
([xs]
(if (nil? (seq xs))
0
(+ 1 (length (rest xs))))))
现在计划或CL所有的例子永远只能这样做了列表,所以这些语言的惯用基本情况测试将是(nil? xs)
。在Clojure中,我们希望这个函数可以在所有类型的集合上工作,例如地理测试(nil? (seq xs))
,或者(empty? xs)
,或者完全不同的东西?
我想考虑的另一种情况是遍历树,即遍历表示树的列表或向量,例如树。 [1 2 [3 4]
。
例如,在一棵树的计算节点:
(defn node-count [tree]
(cond (not (coll? tree)) 1
(nil? (seq tree)) 0
:else (+ (node-count (first tree)) (node-count (rest tree)))))
这里我们使用(not (coll? tree))
检查原子,而在方案/ CL,我们会使用atom?
。我们还使用(nil? (seq tree))
来检查一个空集合。最后,我们使用first
和rest
将当前树解构到左侧分支和树的其余部分。
所以总结一下,有以下几种形式Clojure中惯用:
(nil? (seq xs))
来测试空收集(first xs)
和(rest xs)
钻进去收集(not (coll? xs))
检查原子
感谢您的回答。关于'rest' /'next',所以你说我应该在递归调用中使用'(length(next xs))',因为我打算在集合上调用'seq'呢?至于'coll?',此时我只对本地的Clojure集合类型感兴趣,所以'coll?'应该对我很好。 – liwp 2012-02-10 11:39:02
不客气。我主要是直接调用'seq'作为'rest'的返回值(例如'(if-let [new-xs(seq(rest xs))] ...)'),其中的成语绝对是'(next xs)'和'rest',这只有在下一次迭代中实际上不会在返回值上调用seq时才有意义。在你的'length'函数的情况下,我可能仍然会使用'next'来尽可能清楚地说明函数是严格的,但我认为它没有太大的区别。 – 2012-02-10 18:04:28
好的,我明白了 - 有道理。 – liwp 2012-02-10 20:17:14