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

Reply via email to