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

Reply via email to