On Sep 14, 1:48 pm, Josh Daghlian <[EMAIL PROTECTED]> wrote: > So I'm trying to write a macro that will create a bunch of named (refs > to) structs. What's baffling is that it actually works, in that it > creates the named struct refs as I want, but _then_ throws > AFn.throwArity(). I'm wracking my brain for forgotten macrology > lessons from On Lisp, but this one fails me. Anyone have any ideas? > > Transcript on a freshly launched clojure repl: > > user=> (defstruct thing :property-a :property-b) > #'user/thing > user=> (defmacro make-thing-refs > [r & rs] > (for [ref-name (cons r rs)] > `(def ~ref-name (ref (struct thing))))) > nil > user=> (make-thing-refs a b c d) > java.lang.IllegalArgumentException: Wrong number of args passed to: > PersistentStructMap > java.lang.IllegalArgumentException: Wrong number of args passed to: > PersistentStructMap > at clojure.lang.AFn.throwArity(AFn.java:460) > at clojure.lang.AFn.invoke(AFn.java:71) > at clojure.lang.Ref.invoke(Ref.java:237) > at clojure.lang.Var.invoke(Var.java:327) > at user.eval__2297.invoke(Unknown Source) > at clojure.lang.Compiler.eval(Compiler.java:3891) > at clojure.lang.Repl.main(Repl.java:75) If you are having a problem with a macro the first thing to try is macroexpand: (macroexpand '(make-thing-refs a b c d)) -> ((def a (clojure/ref (clojure/struct user/thing))) (def b (clojure/ref (clojure/struct user/thing))) (def c (clojure/ref (clojure/struct user/thing))) (def d (clojure/ref (clojure/struct user/thing)))) So, your macro expands into a list of defs, which the compiler is going to see as a call. Since the first element in the list is not a special op or macro, its gets evaluated normally, as do all of the other 'args'. Then, the result of the first def (a var) is 'called'. When vars are treated as fns, they delegate to their values. In this case the value is a ref. Refs, too, implement IFn in terms of a call to their values. The value of the ref is a thing, which is a StructMap, which too implements IFn as a one-argument call expecting a key to look up in the map. In this case the structmap's invoke is being passed 3 args, which is more than it expects, thus the arity exception. The bottom line is if you want a macro to expand into more than one expression (in this case you want N defs), then you should emit them inside a do. Rich --~--~---------~--~----~------------~-------~--~----~ 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 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 -~----------~----~----~----~------~----~------~--~---