recursion - 在 Clojure 中将结果累积到向量中的最佳方法? (纯功能代码看起来丑陋和冗长)

标签 recursion clojure functional-programming lisp

...也许使用可变数据的命令式编程在我的大脑中钻得太深了,但我发现在 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)

或者,如果您更愿意使用 mapmapcat 等函数构建它,而不是使用 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/

相关文章:

list - 如何将一个巨大的文件加载到 Racket 中的字符串或列表中?

javascript - 总结给定级别的树(嵌套对象)

javascript - 使用递归组合数组值,即使它们是空的

function - Clojure:在函数列表上的单个值上运行映射

macros - clojure defmacro 中的多重性

scala - 实现列表#flatMap

haskell - 为什么尾递归模数可以优化?

algorithm - 简化递归均值计算

loops - 为什么 Clojure 的范围只迭代 32 次?

Python 函数式方法 : remove key from dict using filter