Awesome! Thanks so much! Anthony
On Sep 7, 2:10 am, Meikel Brandmeyer <m...@kotka.de> wrote: > 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