Interesting -- it's certainly more generic than the solution that I have worked up. I'd need to add something for the variadic fall-back call.
Thank you! Francis Avila <[email protected]> writes: > 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 >> >> -- Phillip Lord, Phone: +44 (0) 191 208 7827 Lecturer in Bioinformatics, Email: [email protected] School of Computing Science, http://homepages.cs.ncl.ac.uk/phillip.lord Room 914 Claremont Tower, skype: russet_apples Newcastle University, twitter: phillord NE1 7RU -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to [email protected] Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to [email protected] 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 [email protected]. For more options, visit https://groups.google.com/d/optout.
