...也许使用可变数据的命令式编程在我的大脑中钻得太深了,但我发现在 Clojure 中构建数据向量的代码冗长、笨拙且令人费解。一定有更好的方法!
在 Ruby 中我可能会写这样的代码:
results = []
a_collection.each do |x|
x.nested_collection.each do |y|
next if some_condition_holds
results << y
end
end
在 Clojure 中,我不知道有比使用递归函数更好的方法来做到这一点,也许就像下面的(可怕的)代码:
; NEWBIE ALERT! NEWBIE ALERT!
(loop [results []
remaining a_collection]
(if (empty? remaining)
results
(recur
(loop [results results
nested (nested_collection (first remaining))]
(if (empty? nested)
results
(if (some_condition_holds)
(recur results (rest nested))
(recur (conj results (first nested)) (rest nested)))))
(rest remaining))))
没有可变数据和迭代循环,您需要使用递归来构建集合。每个这样的递归函数都需要一个 (empty?)
保护子句,等等。整个事情重复得让我想尖叫。
在简单的情况下,map
就足够了,但我正在考虑有多层嵌套的情况,并且在每一层,可能存在需要跳过迭代的条件。
在 Common Lisp 中,我可能会使用 loop
宏或 mapcan
。 Clojure 没有类似 mapcan
的东西吗?
最佳答案
按照我认为这些选项看起来有多好降序排列:
(for [x coll,
y (nested-collection x)
:when (not (some-condition-holds y))]
y)
或者,如果您更愿意使用 map
和 mapcat
等函数构建它,而不是使用 for
语法:
(mapcat (fn [x]
(remove some-condition-holds
(nested-collection x)))
coll)
如果你真的热衷于它,你也可以使用偏函数应用和组合来构建它:
(mapcat (comp (partial remove some-condition-holds)
nested-collection)
coll)
第三种风格在 Clojure 中读起来不太好,尽管在其他一些语言中的等效代码非常好。例如,在 Haskell 中:
coll >>= (filter (not . someConditionHolds) . nestedCollection)
关于recursion - 在 Clojure 中将结果累积到向量中的最佳方法? (纯功能代码看起来丑陋和冗长),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11301998/