Search code examples
clojurelist-comprehensionvariadic

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


What's a good way to create a variadic 'for' in Clojure?

I wrote this out:

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

So I can use this like:

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

and the result will be every possible sum, where each given collection represents the possible values for that binding.

Is there a better way to do this? I don't know of anything in the Clojure core that is used to create all permutations in this way, other than 'for'.


Solution

  • Maybe 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)