Каковы правила разрешения символов как макросов по сравнению с параметрами функции?

Я был удивлен, обнаружив, что альфа-преобразование небезопасно в Clojure:

Clojure> ((fn [o] (o 3 2)) +)
5

Clojure> ((fn [or] (or 3 2)) +)
3

Clojure> ((fn [def] (def 3 2)) +)
java.lang.RuntimeException: First argument to def must be a Symbol

(Я ожидал, что все три фрагмента оцениваются в 5).

Каковы правила для разрешения символов при теневом копировании, макросах и специальных формах?

Я использую версию на Try Clojure.

2 ответа

Вы не можете скрывать специальные формы, согласно документации:

Символ разрешен:

  • Если он квалифицирован пространством имен, значение является значением привязки глобальной переменной, названной символом. Это ошибка, если не существует глобальной переменной, названной символом, или если ссылка на непубличную переменную в другом пространстве имен.
  • Если он квалифицирован пакетом, значением является класс Java, названный символом. Это ошибка, если нет класса, названного символом.
  • ** Иначе, он не квалифицирован и применяется первое из следующего:
    1. Если он называет специальную форму, он считается специальной формой и должен использоваться соответствующим образом.**
    2. В текущем пространстве имен выполняется поиск, чтобы увидеть, существует ли сопоставление символа с классом. Если это так, считается, что символ называет объект класса Java. Обратите внимание, что имена классов обычно обозначают объекты классов, но обрабатываются специально в определенных специальных формах, например, '.' и новый.
    3. Если в локальной области (то есть в определении функции), поиск выполняется, чтобы увидеть, называет ли он локальную привязку (например, аргумент функции или имя с привязкой к имени). Если это так, значение является значением локальной привязки.
    4. В текущем пространстве имен выполняется поиск, чтобы увидеть, существует ли отображение символа на переменную. Если это так, значение является значением привязки переменной, на которую ссылается символ.
    5. Это ошибка.

И я не уверен, но я интерпретирую этот отрывок (с той же страницы) как означающий, что вы также не можете скрывать макросы:

Макросы - это функции, которые манипулируют формами, позволяя использовать синтаксическую абстракцию. Если оператор вызова является символом, который называет глобальную переменную, которая является макро-функцией, эта макро-функция вызывается и передается неоцененным формам операндов. Возвращаемое значение макроса затем оценивается на его месте.

Если оператор не является специальной формой или макросом, вызов считается вызовом функции.

Первые два для меня оцениваются в 5 (Clojure 1.4 в Eclipse / против часовой стрелки REPL). Я подозреваю, что есть ошибка в Try Clojure, если вы получаете 3.

Вы должны иметь возможность локально скрывать как имена функций, так и макросы (хотя это часто не очень хорошая идея, поскольку это может привести к некоторым тонким и запутанным ошибкам!).

Третий не будет работать, потому что def это особая форма. Специальные формы получают специальную обработку от читателя Clojure и / или компилятора, поэтому вы не можете их скрывать.

Другие вопросы по тегам