This is exactly the approach to take: a macro which expands to a defn with all your arities filled out.
Here's a simple approach which might be enough for your problem: it will splice in argument names whenever some marker symbol is encountered, and repeat for the range of arities you want. (defn splice [marker replacement form] (cond (seq? form) (reduce #(if (= marker %2) (into %1 (reverse replacement)) (conj %1 (splice marker replacement %2))) () (reverse form)) (or (vector? form) (set? form)) (reduce #(if (= marker %2) (into %1 replacement) (conj %1 (splice marker replacement %2))) (empty form) form) (map? form) (reduce-kv #(assoc %1 (splice marker replacement %2) (splice marker replacement %3)) {} form) (= marker form) (throw (ex-info "Cannot splice into a top-level form!" {})) :else form)) (defmacro defvariadic ;; Full support for defn options (attr-map, docstring, pre/post conditions) ;; an exercise for the reader. [name marker max-arity params & body] (assert (and (symbol? name) (nil? (namespace name)))) (assert (and (symbol? marker))) (assert (and (integer? max-arity) (<= 0 max-arity 24))) (assert (vector? params)) (let [arg-syms (mapv gensym (subs "abcdefghijklmnopqrstuvwxyz" 0 max-arity)) params+bodies (map (fn [arity] (let [var-params (subvec arg-syms 0 arity)] (list* (splice marker var-params params) (splice marker var-params body)))) (range max-arity))] `(defn ~name ~@params+bodies))) This produces output like the following: (clojure.pprint/pprint (macroexpand-1 '(defvariadic default-ontology-dispatch <> 5 [f <>] (dispatch f <>)))) (clojure.core/defn default-ontology-dispatch ([f] (dispatch f)) ([f a23733] (dispatch f a23733)) ([f a23733 b23734] (dispatch f a23733 b23734)) ([f a23733 b23734 c23735] (dispatch f a23733 b23734 c23735)) ([f a23733 b23734 c23735 d23736] (dispatch f a23733 b23734 c23735 d23736))) On Thursday, June 4, 2015 at 11:55:23 AM UTC-5, Phillip Lord wrote: > > > I have a number of fairly nasty functions with a form that looks like > this: > > (defn default-ontology > ([f] > (dispatch f)) > ([f a] > (dispatch f a)) > ([f a b] > (dispatch f a b)) > ([f a b c] > (dispatch f a b c)) > ([f a b c d] > (dispatch f a b c d)) > ([f a b c d e] > (dispatch f a b c d e)) > ([f a b c d e fa] > (dispatch f a b c d e fa)) > ([f a b c d e fa g] > (dispatch f a b c d e fa g)) > ([f a b c d e fa g h] > (dispatch f a b c d e fa g h)) > ([f a b c d e fa g h i] > (dispatch f a b c d e fa g h i)) > ([f a b c d e fa g h i j] > (dispatch f a b c d e fa g h i j))) > > The reason for all of this is that I need to avoid the use of variadic > function calls for performance reasons -- this function gets called a > lot in my code base, and without this unwinding, I box and unbox > consistantly. > > Now, I dislike the code repetition here, and indeed have found already > found one bug in my code where I missed a variable out, something like.... > > ([f a b c d] > (dispatch f a b d)) > > which is hard to pick up on. > > I can't make the whole thing a macro because I need to pass this as a > first class function. And I can't macro each of the variadic elements > since the I'd need to return two elements at once. > > The best I have done up with so far is: > > (defn ^:private form-with-arity[n] > ;; left as an exercise for the reader > ) > > (defmacro ^:private m-default-ontology > `(defn default-ontology > ~@(map form-with-arity (range 1 10)))) > > (m-default-ontology) > > Or am I missing something more obvious? > > Phil > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.