Monday, July 27, 2015

Remarks on gensym example

Chapter 9 (Writing Macros) of Brave Clojure gives the following example, for the usage of gensym:
(def message "Good job!")

(defmacro without-mischief
  [& stuff-to-do]
  (let [macro-message (gensym 'message)]
    `(let [~macro-message "Oh, big deal!"]
       ~@stuff-to-do
       (println "I still need to say: " ~macro-message))))

(without-mischief
  (println "Here's how I feel about that thing you did: " message))
Result:
Here's how I feel about that thing you did:  Good job!
I still need to say:  Oh, big deal!

One important thing to note is, that the symbol in the macro ('macro-message') in fact does not have to be named differently than the global symbol. It works also with the same name:
(def message "Good job!")

(defmacro without-mischief
  [& stuff-to-do]
  (let [message (gensym 'message)]
    `(let [~message "Oh, big deal!"]
       ~@stuff-to-do
       (println "I still need to say: " ~message))))

(without-mischief
  (println "Here's how I feel about that thing you did: " message))
Result:
Here's how I feel about that thing you did:  Good job!
I still need to say:  Oh, big deal!


On the other hand, just giving a different name to the symbol within the macro won't work:
(def message "Good job!")

(defmacro with-mischief
  [& stuff-to-do]
  `(let [macro-message "Oh, big deal!"]
     ~@stuff-to-do))

(with-mischief
  (println "Here's how I feel about that thing you did: " message))
Result:
CompilerException java.lang.RuntimeException: 
Can't let qualified name: user/macro-message, compiling:(NO_SOURCE_PATH:1:1)

Finally, in case the symbol is a parameter of the macro, then it is possible to bind it, without gensym:
defmacro echoit
    [message]
    (let [message (str "echo: " message)] message))
(echoit "hello")
Result:
"echo: hello"

No comments:

Post a Comment