Умышленное ограничение имени символа Clojure или унаследованное? - PullRequest
4 голосов
/ 02 августа 2010

В Common LISP я могу сделать:

(setf a1 'a)
(setf 1a 'b)

В clojure я могу сделать первое (игнорируя тот факт, что setf и def работают по-разному)

(def a1 'a)

, но со вторымЯ получаю сообщение об ошибке

(def 1a 'b)

java.lang.NumberFormatException: Invalid number: 1a

Clojure просто унаследовал это ограничение от Java или это преднамеренно?(то есть вы не можете иметь имя класса, переменную или имя метода в Java с этим стилем - поэтому я предполагаю, что оно только что перенесено.)

1 Ответ

11 голосов
/ 02 августа 2010

Символьные литералы Clojure задокументированы , чтобы начинать с нецифрового символа. Это не имеет ничего общего с идентификатором Java или числовым литеральным синтаксисом - литерал символа Clojure - это любой метод clojure.lang.LispReader read, считываемый как символ, и в литералах символа Clojure допустимо несколько символов, которые не допускаются в Идентификаторы Java (например, -, > ...; есть также схема для их преобразования в последовательности символов, такие как _GT_ для > для целей взаимодействия). Непосредственной причиной ошибки является то, что clojure.lang.LispReader/read отправляется на readNumber сразу же после того, как увидит цифру, и нет способа "отступить" от нее.


Тангенциальное обсуждение ради полноты.

Обратите внимание, что если вы создаете символ вручную, вы можете использовать его для именования Var:

;; Clojure's intern serves a different purpose to CL's intern, see (doc intern)
user> (intern *ns* (symbol "1+") inc)
#'user/1+
user> ((ns-resolve *ns* (symbol "1+")) 1)
2

Вы даже можете делать такие забавные вещи, как

user> (eval `(defrecord ~(symbol "1foo") []))
user.1foo
user> user.1foo
user.1foo
user> (user.1foo.)
#:user.1foo{}

... что, конечно, совершенно безумно, хотя, возможно, не так сильно, как

user> (in-ns (symbol "1foo"))
#<Namespace 1foo>
1foo> (clojure.core/refer-clojure)
nil
1foo> (defrecord Foo [])
1foo.Foo
1foo> (in-ns 'user)
#<Namespace user>
user> (1foo.Foo.)
; Evaluation aborted.   ;; can't do that
user> (eval `(new ~(symbol "1foo.Foo")))
#:1foo.Foo{}

Я полагаю, что если кто-то будет настаивать на подобных действиях, он в конечном итоге столкнется с ограничениями JVM. Конечно, нет смысла делать это ... В любом случае, возвращаясь к первоначальному вопросу, ошибка, вызванная 1+, связана с синтаксисом буквального символа, который является дружественным к Java только в той степени, в которой разумный "перевод" " существует. Объекты Clojure, имеющие имена, не очень заботятся о том, чтобы эти имена были правильно сформированы или иным образом, хотя использование таких имен является громоздким и определенно не поддерживается.

user.1foo из приведенного выше примера на самом деле является классом Java - я немного удивлен, увидев, что этот класс действительно работает, хотя, с другой стороны, я, кажется, вспоминаю внутренние ограничения JVM в отношении имен: должен быть менее строгим, чем у Java.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...