绑定数量未知的 Clojure 列表理解(可变 'for')

Clojure list comprehension where the number of bindings is not known (variadic 'for')

在 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 核心中的任何内容

我认为您的宏实现很棒,但将其作为函数实现具有增加可组合性的优势。例如,您可以将 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)

也许cartesian-product from 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)