11.3 Преобразование строк в символы

Значение специальной переменной *package* должно быть всегда объектом пакета (не именем). Данный объект называется текущим пакетом.

Когда Lisp’овый считыватель получает строку для символа, он ищет его по имени в текущем пакете. Данный поиск может привести к поиску в других пакетах, экспортированные символы которых унаследованы текущим пакетом. Если имя найдено, то возвращается соответствующий символ. Если имя не найдено (то есть, в текущем пакете не существует соответствующего доступного символа), то создаётся новый символ и помещается в текущий пакет. Если точнее, то текущий пакет становится владельцем (домашним пакетом) символа. Если это имя будет прочитано ещё раз позже и в этом же пакете, то будет возвращён уже созданный символ.

Часто необходимо сослаться на внешний символ в некотором другом, не текущем пакете. Это может быть сделано с помощью полного имени, включающем имя пакета, затем двоеточие, и, наконец, имя символа. Это приводит к поиску символа в указанном, а не текущем пакете. Например, editor:buffer ссылается на внешний символ с именем buffer доступный из пакета с именем editor, вне зависимости от того, есть ли в текущем пакете символ с таким же именем. Если пакета с именем editor или символа с именем buffer в указанном пакете не сущетсвует, Lisp’овый считыватель сигнализирует исправимую ошибку.

В редких случаях пользователь может нуждаться в ссылке на внутренний символ некоторого не текущего пакета. Это нельзя сделать с помощью двоеточия, так как данная запись позволяет ссылаться только на внешние (экспортированный) символы. Однако, это можно сделать с помощью двойного двоеточия ::, указанного вместо одинарного. Если используется editor::buffer, то эффект такой же, как если бы произошла попытка найти символ с именем buffer и *package* была связана с пакетом editor. Двойное двоеточие должно использоваться с осторожностью.

Пакет с именем keyword содержит все ключевые символы используемые Lisp’овой системой и пользовательским кодом. Такие символы должны быть легко доступны из любого пакета, и конфликт имён не является проблемой, так как эти символы используются только в качестве меток и не содержат значений. Так как ключевые символы используются часто, то для них Common Lisp предоставляет специальный синтаксис. Любой символ с двоеточием в начале и без имени пакета (например :foo) добавляется (или ищется) в пакете keyword как внешний символ. Пакет keyword также отличается тем, что при добавлении в него символа, последний автоматически становится внешним. Символ также автоматически декларируется как константа (смотрите defconstant) и его значением становится он сам. В целях хорошего стиля, ключевые символы должны быть всегда доступны с помощью двоеточия в начале имени. Пользователь никогда не должен импортировать или наследовать ключевые символы в другие пакеты. Попытка использовать use-package для пакета keyword является ошибкой.

Каждый символ содержит ячейку пакета, которая используется для записи домашнего пакета символа, или nil, если символ беспакетный. Эта ячейка доступна с помощью функции symbol-package. Когда пакетный символ выводится в поток, если это символ в пакете ключевых символов keyword, тогда он выводится с двоеточием в начале, иначе, если он доступен (напрямую или унаследовано) в текущем пакете, он выводится без имени пакета, иначе он выводится полностью, с именем пакета, именем символа и : в качестве разделителя для внешнего символа, и :: для внутреннего.

Символ, у которого слот (ячейка) пакета содержит nil (то есть, домашний пакет отсутствует) печатается с #: в начале имени. С использованием import и unintern возможно создать символ, который не имеет домашнего пакета, но фактически доступен в некоторых пакетах. Lisp система не проверяет такие патологические случаи, и такие символы будут всегда печататься с предшествующими #:.

В целом, синтаксис имён символов может быть выражен в следующих четырёх примерах.

Все другие использования двоеточия внутри имен символов не определены Common Lisp’ом, но зарезервированы для реализаций. Сюда включены имена с двоеточием в конце, или содержащими два и более двоеточиях или просто состоящими из двоеточия.