Clojure: как оценить цитируемую форму в локальном объеме? - PullRequest
5 голосов
/ 14 ноября 2011

Я хочу определить макрос, который случайным образом выбирает одно из заданных выражений и оценивает его. Например,

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

2 голосов
/ 14 ноября 2011

Вы не можете оценить значение времени выполнения в лексической среде, которая существует только во время компиляции. Решение состоит в том, чтобы использовать 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 голос
/ 14 ноября 2011

Только не цитируйте вызов rand-nth или выражения.Это будет делать то, что вы хотите:

(defmacro equal-chance
  [& exprs]
    (rand-nth exprs))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...