Hi, first of all we should start with the form we finally want to have:
(defrecord Foo [a b c]) (defn make-Foo [& {:keys [a b c] :or {a :x c :z}}] (Foo. a b c)) ; Use as: (make-Foo :b :f) => (Foo. :x :f :z) The only annoying part is the boilerplate of defining make-Foo. What we would like to write is: (defrecord+ Foo [[a :x] b [c :z]]) So how do we get from the lower form to the upper form? Basically you have that already, but you should not make the constructor a macro, but a function. General note: You want to use almost always vectors instead of lists to group things. Vectors are the Right Tool here. Lists are much less in important in Clojure than in other Lisp-like languages. Besides their role in code representation. (Note: a seq is not a list) Then we have to define the constructor function. Here we exploit the "old" new operator to save us from modifying the type symbol. Well, and that's basically it. There is no need for eval and related dark magic. (defmacro defrecord+ [record-name fields-and-values & record-body] (let [fields-and-values (map #(if (vector? %) % [% nil]) fields-and- values) fields (vec (map first fields-and-values)) default-map (into {} fields-and-values)] `(do (defrecord ~record-name ~fields ~...@record-body) (defn ~(symbol (str "make-" (name record-name))) [& {:keys ~fields :or ~default-map}] (new ~record-name ~...@fields))))) And the result: user=> (defrecord+ Foo [[a :x] b [c :z]]) #'user/make-Foo user=> (make-Foo :b :f) #:user.Foo{:a :x, :b :f, :c :z} user=> (macroexpand-1 '(defrecord+ Foo [[a :x] b [c :z]])) (do (clojure.core/defrecord Foo [a b c]) (clojure.core/defn make-Foo [& {:or {a :x, b nil, c :z}, :keys [a b c]}] (new Foo a b c))) (macroexpand output formatted for readability) This can be easily extended, that the constructor also allows arbitrary other keywords, besides the usual defined fields. This is left to the astute reader as an excerise. ;) Hint: there is also :as in destructuring. Bottom line: Avoid macros at all cost! If a function does the job, use a function! They are easier to write, can be passed around, can be apply'd, ... Hope this helps. Sincerely Meikel -- 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