Unquoting construction in contextual-eval in The Joy of Clojure -
the following code chapter 8.1.1 of (the second edition of) the joy of clojure fogus, houser:
(defn contextual-eval [ctx expr] (eval `(let [~@(mapcat (fn [[k v]] [k `'~v]) ctx)] ; build let bindings @ compile time ~expr))) (contextual-eval '{a 1, b 2} '(+ b)) ;;=> 3 (contextual-eval '{a 1, b 2} '(let [b 1000] (+ b))) ;;=> 1001
i not understand meaning of construction `'~v
. can please elaborate on that?
in book, said that
the bindings created use interesting `'~v pattern garner value of built bindings @ runtime.
for example
(contextual-eval '{a 1, b 2} '(+ b))
is expanded
(let [a '1 b '2] (+ b)))
and don't understand why quotes introduced, for.
also, have following behaviour:
(contextual-eval '{a 1, b (+ 1)} '(+ b)) classcastexception clojure.lang.persistentlist cannot cast java.lang.number (defn contextual-eval' [ctx expr] (eval `(let [~@(mapcat (fn [[k v]] [k v]) ctx)] ~expr))) (contextual-eval' '{a 1, b (+ 1)} '(+ b)) ;=> 3
that expression uses of special line-noise-looking symbols available in clojure, it's worth picking apart:
`
reader-macro "syntax-quote"
"syntax-quote" special among reader macros because can call function via it's short form. can't instance call(syntax-quote something-here )
instead write`something-here
. provides rich set of options specifying parts of expression after should evaluated , should taken literally.'
is reader-macro shortcutquote
special form. causes expression wraps not evaluated, , instead treated data. if wanted write literalquote
form without evaluating it, write`'something
`(quote something)
result. , cause resulting quote expression not evaluated, returned without running yet.~
part of syntax of syntax-quote (it's "quote" syntax) means "actually let part run" if have big list want taken literally (not run right now), except have 1 item want evaluated right now, write`(a b c ~d e f g)
, d thing in list gets evaluated whatever it's defined be.
so can put together:
`'~
means "make quote expression contains value of v right now"
user> (def v 4) #'user/v user> `'~v (quote 4)
and on motivation fancyness:
(contextual-eval '{a 1, b 2} '(+ b))
seems adding thinking without benefit because it's quoting values 1 , 2. since these proper "values" never change anyway.
now if expression instead:
(contextual-eval '{a (slurp "https://example.com/launch?getcode") b the-big-red-button} '(press b a))
then make more sense careful when particular bit of code runs. pattern controlling phase of programs life runs code. clojure has several "times" when code can run:
- at macro-evaluation time: while code being formed. (side effects here require forethought).
- when namespaces loading: when forms @ top level run. happens when start program , before
main
invoked. - things run result of running
main
ps: above definitions tailored context of question , not intended use "official" terms.
Comments
Post a Comment