Clojure:如何在本地范围内评估引用的表单?
我想定义一个宏,随机选择一个给定表达式并对其求值。比如说,Clojure:如何在本地范围内评估引用的表单?,clojure,Clojure,我想定义一个宏,随机选择一个给定表达式并对其求值。比如说, (equal-chance (println "1") (println "2")) (let [x 10] (eval '(println x))) 一半时间打印“1”,另一半时间打印“2” 我试着用 (defmacro equal-chance [& exprs] `(rand-nth '~exprs)) 但这将返回一个引用的表单,而不是对其进行计算(即,它将返回(println“1”),而不是实际
(equal-chance
(println "1")
(println "2"))
(let [x 10] (eval '(println x)))
一半时间打印“1”,另一半时间打印“2”
我试着用
(defmacro equal-chance
[& exprs]
`(rand-nth '~exprs))
但这将返回一个引用的表单,而不是对其进行计算(即,它将返回(println“1”)
,而不是实际打印“1”)。我不能使用eval
,因为它不保留绑定。比如说,
(equal-chance
(println "1")
(println "2"))
(let [x 10] (eval '(println x)))
投诉无法解析符号x
是否有方法在本地范围内评估引用的表单?或者有更好的方法来解决这个问题?只是不要引用对
rand nth
或表达式的调用。这将满足您的要求:
(defmacro equal-chance
[& exprs]
(rand-nth exprs))
不能在仅在编译时存在的词法环境中计算运行时值。解决方案是使用
fn
而不是quote
,使用函数调用而不是eval
:
(defmacro equal-chance [& exprs]
`((rand-nth [~@(map (fn [e] `(fn [] ~e)) exprs)])))
其工作方式是将
(equal chance e1 e2…
扩展为((rand nth[(fn[]e1)(fn[]e2)…])
,这非常有效!我自己永远也不会想到这一点,谢谢。我更喜欢使用delay/force而不是fn/call:(force(rand nth[~@(map(partial list`delay)exprs)])
这并不适用于所有情况(dotimes[i10](相等概率1,2,3))
将返回其中一个数字10次。