Your solution with map-ps is quite elegant. I was actually a little annoyed that I had to deal with different data structures when walking through Clojure code, as opposed to Lisp/Scheme code.
The doall was necessary for my use-case actually. Some of the macros I write interact with the environment (ie. they're not side-effect free). So I had to ensure that macroexpand-all actually *does* run all the macros appropriately. -Patrick On Feb 10, 6:29 pm, Ken Wesson <kwess...@gmail.com> wrote: > On Thu, Feb 10, 2011 at 11:01 AM, CuppoJava <patrickli_2...@hotmail.com> > wrote: > > Thanks for all your help everyone! > > > So I came up with an elegant solution. It was a combination of > > Meikel's codwalker solution gave me the idea to bootstrap off of > > Clojure's macroexpand system to get it to work. > > > ;;This is a convenience method for expanding macros. It recursively > > ;;macroexpands every subform within a form. > > (defn macroexpand-full [expression] > > (let [expanded (macroexpand expression)] > > (cond > > ;;Normal Form > > (or (seq? expanded) (list? expanded)) > > (doall (map macroexpand-full expanded)) > > > ;;Vector Form > > (vector? expanded) > > (vec (map macroexpand-full expanded)) > > > ;;Map Form > > (map? expanded) > > (into {} (map macroexpand-full expanded)) > > > ;;Set Form > > (set? expanded) > > (into #{} (map macroexpand-full expanded)) > > > ;;Atom > > :else > > expanded))) > > What a coincidence. I just had reason to write my own version of this. > I came up with a somewhat different approach though: > > (defn map-ps [f coll] > (if (map? coll) > (into (empty coll) > (map (fn [[k v]] [(f k) (f v)]) coll)) > (if (or (vector? coll) (set? coll)) > (into (empty coll) (map f coll)) > (map f coll)))) > > (defn macroexpand-all [form] > (if (coll? form) > (let [f (macroexpand form)] > (if (coll? f) > (map-ps macroexpand-all f) > f)) > form)) > > The helper function map-ps maps a function over any set, map, vector, > or seq/list, preserving the type and applying to both keys and values > of maps. (It should even turn a sorted-set, say, into a sorted-set > with the same comparator. That may actually work poorly in certain > cases where the types of the elements are changed. But that's not > relevant for macroexpand-all. Meanwhile all lists/seqs become > LazySeq.) > > The actual macroexpand-all function exploits macroexpand, as does your > implementation, but uses map-ps to recursively apply itself to > subforms. > > I didn't bother with doall because typical Clojure code does not nest > thousands of parentheses deep. :) -- 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