【发布时间】:2014-04-17 00:36:10
【问题描述】:
我刚开始玩 Clojure。
如何遍历项目向量?
我的幼稚递归函数将具有类似于经典地图的形式,例如。
(defn map [f xs] (
(if (= xs [])
[]
(cons (f (first xs)) (map f (rest xs))
)
))
问题是我在网上找不到任何此类代码的示例。我找到了很多使用内置序列遍历函数(如 for、map 和 loop)的示例。但是没有人做原始递归版本。
那是因为你不应该在 Clojure 中做这种事情吗? (例如,因为它使用了没有尾调用优化的低级 Java 原语?)?
【问题讨论】:
-
您提到了尾调用优化,但请注意,Clojure 没有有尾调用优化,除非明确使用
recur。 -
不要重新定义
map,它已经存在。查看(source map)的顶部附近,您会看到与您编写的代码相同的代码,只是包裹在lazy-seq中。如果您想要一个渴望版本,请使用mapv。您看不到很多显式递归的原因是有更高级别的函数,如reduce、map等,它们以更具表现力的方式处理了许多用例。 -
...所以答案是是的,你不应该在 Clojure 中做这种事情。顺便说一句,通过使用
when-let,标准map代码在空序列上隐式返回nil。当nil被要求成为一个序列时,它伪装成一个空序列,因此恢复了顺序。这称为nil punning。相关摘录是(defn map [f coll] (lazy-seq (when-let [s (seq coll)] (cons (f (first s)) (map f (rest s))))))