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 shortcut quote special form. causes expression wraps not evaluated, , instead treated data. if wanted write literal quote 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

Popular posts from this blog

php - Wordpress website dashboard page or post editor content is not showing but front end data is showing properly -

javascript - Get parameter of GET request -

javascript - Twitter Bootstrap - how to add some more margin between tooltip popup and element -