我想定义一个宏,它随机选择一个给定的表达式并对其进行求值。例如,
(equal-chance
(println "1")
(println "2"))
应该在一半的时间打印“1”而在另一半打印“2”。
我尝试过使用,
(defmacro equal-chance
[& exprs]
`(rand-nth '~exprs))
但是这会返回一个引用的表单,而不是对其进行评估(即它将返回(println "1")
而不是实际打印“1”)。我不能使用eval
因为它不保留绑定。例如,
(let [x 10] (eval '(println x)))
抱怨它无法解析符号x。
有没有办法在本地范围内评估引用的表单?或者也许有更好的方法来解决这个问题?
答案 0 :(得分:2)
您无法在仅在编译时存在的词法环境中评估运行时值。解决方案是使用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) ...]))
。
答案 1 :(得分:1)
只是不要引用对rand-nth
或表达式的调用。这将做你想要的:
(defmacro equal-chance
[& exprs]
(rand-nth exprs))