Clojure:如何评估本地范围内的引用形式?

时间:2011-11-14 16:08:30

标签: clojure

我想定义一个宏,它随机选择一个给定的表达式并对其进行求值。例如,

(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。

有没有办法在本地范围内评估引用的表单?或者也许有更好的方法来解决这个问题?

2 个答案:

答案 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))