On Mon, Jul 27, 2009 at 8:33 PM, nchubrich <nicholas.chubr...@gmail.com>wrote:

>   Anyway I'd appreciate any critiques of the implementation; whether
> it's a useful thing or not; if there are more idiomatic ways of doing
> the same thing; and, if yes-no to the aforetwo, where's the best place
> to add this functionality?


Well, it won't actually work properly at run-time, and won't work with a
multiple-expression body. Try:

(defmacro i-let [bindings & body]
 (assert-args i-let
   (vector? bindings) "a vector for its bindings"
   (= 0 (mod (count bindings) 3)) "forms by three in binding vector")
 (if (empty? bindings)
   `(let ~bindings ~body)
 `(let [nom# ~(bindings 0)
        attempted-val# ~(bindings 1)
        nil-val# ~(bindings 2)]
   (if (nil? attempted-val#)
    (let [~nom# ~nil-val#] (i-let ~(vec (drop 3 bindings)) ~...@body))
    (let [~nom# ~attempted-val#] (i-let ~(vec (drop 3 bindings))
~...@body))))))

though I'm somewhat dubious about it producing trees of nested lets instead
of a single let, with many copies of the body, too; why not

(defmacro i-let [bindings & body]
  (assert-args i-let
    (vector? bindings) "a vector for its bindings"
    (= 0 (mod (count bindings) 3)) "forms by three in binding vector")
  `(let
     ~(vec
        (reduce concat
          (map
            #(list
               (first %)
               `(let [x# ~(second %)]
                  (if (nil? x#)
                    ~(second (rest %))
                    x#)))
            (partition 3 bindings))))
     ~...@body))

Input:
(i-let [x (foo) 0
        y (:key strct) (:key default-map)]
  (swap! foo bar baz)
  (inc x))

Output:
(let [x (let [x__1034__auto__ (foo)]
          (if (nil? x__1034__auto__)
            0
            x__1034__auto__))
      y (let [x__1034__auto__ (:key strct)]
          (if (nil? x__1034__auto__)
            (:key default-map)
            x__1034__auto__))]
  (swap! foo bar baz)
  (inc x))

Note that this just automates what you said you were too lazy to do, write
an if for every binding. This is generally how best to do macros: make them
generate the same code you'd otherwise write manually. :)

(You can test it yourself using macroexpand-1 if you want to.)

--~--~---------~--~----~------------~-------~--~----~
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