I realize the following is a bad idea for many reasons. I also realize that given I have a stackoverflow rep of 23, it\'s nature to assume that I\'m a newb learning to progr
Dynamic binding exists for a reason and it has lots of great uses, so no worries about being flamed for seeking to understand it :-) There is some confusion floating around many older Clojure tutorials that pre-date the need for adding ^:dynamic metadata to vars that you expect to dynamically rebind.
This first example uses dynamic binding by rebinding an existing name. This removes the need for the macro to introduce a new symbol:
(def dog {:sound #(str "wooooof")})
(def cat {:sound #(str "mewwww")})
define the function we will be rebinding to be dynamic (which allows rebinding)
(defn :^dynamic speak [] (println "eh?"))
write a basic template macro to bind speak to the function in the animal:
(defmacro with-animal [animal & body]
`(binding [speak (:sound ~animal)]
~@body))
and test it:
(with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
speak into the scope using a let with no need for dynamic binding. This is not to say that binding is bad in some way, it just more closely fits your desire to not write (let-binding [speak (fn [] "meow")] ...) This type of maco is called anaphoric (if you're into such fancy names):
the important part is the ~' before the speak symbol that explicitly introduces an un-qualified symbol into the scope:
user> (defmacro with-animal [animal & body]
`(let [~'speak (:sound ~animal)]
~@body))
#'user/with-animal
user> (with-animal dog
(println (str "Dog: " (speak) "\n")))
Dog: wooooof
nil