【问题标题】:Clojure list comprehension where the number of bindings is not known (variadic 'for')Clojure 列表理解,其中绑定的数量未知(可变参数“for”)
【发布时间】:2022-02-02 19:53:46
【问题描述】:

在 Clojure 中创建可变参数“for”的好方法是什么?

我写了这个:

(defmacro variadic-for
  [f colls]
  (let [bindings (map (fn [coll] [(gensym) coll]) colls)]
    `(for ~(vec (apply concat bindings))
       (~f ~@(map first bindings)))))

所以我可以这样使用:

(variadic-for + [[1] [2] [3 4]])

结果将是所有可能的总和,其中每个给定集合代表该绑定的可能值。

有没有更好的方法来做到这一点?除了“for”之外,我不知道 Clojure 核心中用于以这种方式创建所有排列的任何内容。

【问题讨论】:

  • 你能澄清一下想要的结果吗?是[6 7]吗?另外,用例是什么?

标签: clojure list-comprehension variadic


【解决方案1】:

也许cartesian-product 来自clojure.math.combinatorics

(defn variadic-for [f colls]
  (map #(apply f %)
        (apply clojure.math.combinatorics/cartesian-product colls)))

(variadic-for + [[1] [2] [3 4]])
=> (6 7)

【讨论】:

    【解决方案2】:

    我认为您的宏实现很棒,但将其实现为函数具有提高可组合性的优势。例如,您可以将 variadic-for 传递给函数。这是variadic-for作为函数的实现:

    (defn combine2 [A B]
      (for [a A
            b B]
        (conj a b)))
    
    (defn combinations [colls]
      (reduce combine2 [[]] colls))
    
    (defn variadic-for [f colls]
      (map #(apply f %) (combinations colls)))
    

    我相信某些库中已经有一个 combinations 函数,但如上所述,自己实现它很容易。

    如果variadic-for 是宏,则无法执行以下操作:

    (def combinatorial+ (partial variadic-for +))
    
    (combinatorial+ [[1] [2] [3 4]])
    ;; => (6 7)
    

    【讨论】:

    • 确定“组合”只是 combine2 的左折叠。聪明!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-19
    • 2019-10-17
    • 1970-01-01
    • 2011-08-29
    • 1970-01-01
    • 1970-01-01
    • 2018-07-06
    相关资源
    最近更新 更多