以下代码来自Fogus,Houser 的Clojure之乐(第二版)第8.1.1章:
(defn contextual-eval [ctx expr]
(eval
`(let [~@(mapcat (fn [[k v]] [k `'~v]) ctx)] ; Build let bindings at compile time
~expr)))
(contextual-eval '{a 1, b 2} '(+ a b))
;;=> 3
(contextual-eval '{a 1, b 2} '(let [b 1000] (+ a b)))
;;=> 1001
Run Code Online (Sandbox Code Playgroud)
我真的不明白建筑的意义`'~v.有人可以详细说明吗?
在书中,只是说
创建的绑定使用有趣的`'~v模式在运行时获取构建的绑定的值.
例如
(contextual-eval '{a 1, b 2} '(+ a b))
Run Code Online (Sandbox Code Playgroud)
扩大到
(let [a '1 b '2] (+ a b)))
Run Code Online (Sandbox Code Playgroud)
我不明白为什么引用这些报价,它们有什么好处.
此外,我们有以下行为:
(contextual-eval '{a 1, b (+ a 1)} '(+ a b))
ClassCastException clojure.lang.PersistentList cannot be cast to java.lang.Number
(defn contextual-eval' [ctx expr]
(eval
`(let [~@(mapcat (fn [[k v]] [k v]) ctx)]
~expr)))
(contextual-eval' '{a 1, b (+ a 1)} '(+ a b))
;=> 3
Run Code Online (Sandbox Code Playgroud)
该表达式使用了几乎所有Clojure中可用的特殊线条噪声符号,因此值得将它分开:
`是一个(syntax-quote something-here )你写的东西`something-here.它提供了一组丰富的选项,用于指定在应该评估表达式之后的哪些部分,以及应该从字面上理解哪些部分.'是quote特殊表单的reader-macro快捷方式.它导致它包装的表达式不被评估,而是被视为数据.如果你想编写一个文字quote形式而不评估它,你可以写作`'something得到`(quote something)结果.这将导致结果引用表达式不被评估,只是按原样返回而不运行它.
~是语法引用的语法的一部分(它是带语法的"引用")意味着"实际上让这部分运行"所以如果你有一个你想要字面意义的大列表(现在不运行),除了你有你真正想要评估的一个项目,然后你可以写,`(a b c ~d e f g)并且d将是该列表中唯一被评估为当前定义的内容的东西.
所以现在我们可以把它们放在一起:
`'~ 表示"制作一个包含v值的引用表达式,因为它现在是"
user> (def v 4)
#'user/v
user> `'~v
(quote 4)
Run Code Online (Sandbox Code Playgroud)
对于这种幻想的动机:
(contextual-eval '{a 1, b 2} '(+ a b))
Run Code Online (Sandbox Code Playgroud)
似乎只是添加一些额外的思维而没有任何好处,因为它基本上只是引用值1和2.因为这些是正确的"值",它们无论如何都不会改变.
现在,如果表达式是:
(contextual-eval
'{a (slurp "https://example.com/launch?getCode")
b the-big-red-button}
'(press b a))
Run Code Online (Sandbox Code Playgroud)
那么,当特定的代码运行时要小心它会更有意义.因此,这种模式是关于控制程序生命的哪个阶段实际运行代码.当代码可以运行时,Clojure有几个"时间":
main调用时,通常会发生这种情况.mainps:以上定义是针对此问题的背景而定制的,并非旨在使用"官方"术语.
| 归档时间: |
|
| 查看次数: |
130 次 |
| 最近记录: |