Last active
January 1, 2016 03:59
-
-
Save cjfrisz/8088647 to your computer and use it in GitHub Desktop.
Macros as text-rearrangers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
;; It often makes sense to think about macros as taking names as arguments. | |
;; This is in contrast to functions which take values as arguments. | |
;; Consider this macro (by a user in the #clojure IRC) | |
(defmacro getter [obj nm] | |
`((memfn ~(read-string (str "get" nm))) ~obj)) | |
;; It takes two names, obj and nm. | |
;; Nothing really interesting happens to obj, so let's focus on what happens with nm: | |
(read-string (str "get" nm)) | |
;; It constructs a string by appending "get" to the string representing the _name_ given by nm, | |
;; and then reads that string as a Clojure datum. | |
;; Consider this expression that uses the getter macro (taken from the same IRC user as above): | |
(defn mine | |
[pdfdoc] | |
(with-open [doc (PDDocument/load pdfdoc)] | |
(let [info (.getDocumentInformation doc)] | |
(getter info "Title")))) ; the name given by nm is the string "Title" | |
;; This macro seems to work when the _name_ given by nm is a datum, as it is above: | |
(macroexpand '(getter info "Title") ; the name given by nm is the string "Title" | |
;; -> ((clojure.core/memfn getTitle) info) | |
;; Things seem to go awry when the getter macro is handed a variable whose _value_ is the | |
;; intended datum, such as in this expression (from the IRC user's question): | |
(defn mine2 | |
[pdfdoc] | |
(with-open [doc (PDDocument/load pdfdoc)] | |
(let [info (.getDocumentInformation doc)] | |
(doseq [wd ["Title" "Subject"]] | |
(do | |
(println "got" wd) | |
(getter info wd)))))) ; The name given by nm is wd | |
(macroexpand '(getter info wd))) ; the name given by nm is wd | |
;; -> ((clojure.core/memfn getwd) info) | |
;; It seems like the intention was to hand the _value_ of wd to getter | |
;; (which would have been "Title" on one iteration, then "Subject on the next"), | |
;; but instead getter received the _name_ of the variable, wd. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment