Переменная область + eval в Clojure - PullRequest
18 голосов
/ 03 июня 2011

В Clojure

(def x 3)
(eval '(prn x))

печатает 3, тогда как

(let [y 3]
   (eval '(prn y)))

и

(binding [z 3] (eval '(prn z)))

генерируют исключение «Невозможно разрешить переменную».

Согласно http://clojure.org/evaluation, eval, load-string и т. Д. Генерируются временные пространства имен для оценки их содержимого.Поэтому я не ожидал, что ни один из приведенных выше примеров кода не сработает, поскольку (def x 3) выполняется в моем текущем пространстве имен, а не в том, что создано eval.

  1. Почему первый пример кодаработать, а не последние два?
  2. Как я могу eval форму со связанными переменными без использования def?

Спасибо!

1 Ответ

15 голосов
/ 03 июня 2011

1 .:

Причина, по которой это не работает (более или менее) приведена на странице, на которую вы ссылаетесь:

It is an error if there is no global var named by the symbol […]

И

[...]

  1. В текущем пространстве имен выполняется поиск, чтобы увидеть, есть ли сопоставление от символа к вар. Если так, то значение является значением привязки переменная, на которую указывает символ.

  2. Это ошибка.

eval оценивает формы в пустой ( null в CL-lingo) лексической среде. Это означает, что вы не можете получить доступ к привязкам лексических переменных из области действия вызывающего. Кроме того, binding создает новые привязки для существующих переменных, поэтому вы не можете использовать его «самостоятельно», не имея declare d или def редактируемых переменных, которые вы пытаетесь связать. Кроме того, лексические переменные (по крайней мере, в CL, но я был бы удивлен, если бы это не относится к Clojure) уже перестали существовать во время выполнения - они переводятся в адреса или значения.

См. Также мой более старый пост на эту тему.

2:.

Итак, вы должны использовать динамические переменные. Вы можете избежать явного def, но вам все равно, по крайней мере, нужно declare их (которые def имен переменных без привязок):

user=> (declare ^:dynamic x)
#'user/x
user=> (binding [x 10] (eval '(prn x)))
10
nil

Кстати: я полагаю, вы знаете, зачем вам нужен eval, и что его использование считается злом , когда другие решения будут уместны.

...