Чтобы понять, как создаются символы в GNU Emacs Lisp, необходимо знать, как Lisp читает их. Lisp должен гарантировать, что он находит один и тот же символ каждый раз, когда читает одну и ту же последовательность символов в одном и том же контексте. Невыполнение этого требования привело бы к полной путанице.
Когда читатель Lisp встречает имя, ссылающееся на символ в исходном коде, он ищет это имя в таблице, называемой обаррей, чтобы найти символ, который имел в виду программист. Обаррей — это неупорядоченный контейнер символов, индексированный по именам.
Читатель Lisp также учитывает «сокращения». Если программист их предоставил, это позволяет читателю найти символ, даже если его имя не присутствует в полной форме в исходном коде. См. Сокращения.
Если символ с нужным именем найден, читатель использует этот символ. Если обаррей не содержит символа с таким именем, читатель создает новый символ и добавляет его в обаррей. Поиск или добавление символа с определенным именем называется интернированием, а символ тогда называется интернированным символом.
Интернирование гарантирует, что каждый обаррей содержит только один символ для любого конкретного имени. Другие символы с таким же именем могут существовать, но не в том же обаррее. Таким образом, читатель получает одни и те же символы для одних и тех же имен, пока вы читаете с использованием того же обаррея.
Интернирование обычно происходит автоматически в читателе, но иногда другие программы могут захотеть сделать это. Например, после того как команда M-x получает имя команды в виде строки с помощью минибуфера, она затем интернирует строку, чтобы получить интернированный символ с этим именем. В качестве другого примера, гипотетическая программа телефонной книги могла бы интернировать имя каждого искомого человека как символ, даже если обаррей не содержал его, чтобы она могла прикрепить информацию к этому новому символу, например, время последнего обращения к нему.
Ни один обаррей не содержит всех символов; на самом деле, некоторые символы не находятся ни в одном обаррее. Они называются неинтернированными символами. Неинтернированный символ имеет те же четыре ячейки, что и другие символы; однако единственный способ получить доступ к нему — найти его в каком-либо другом объекте или как значение переменной. Неинтернированные символы иногда полезны при генерации кода Lisp, см. ниже.
Примечание Common Lisp: В отличие от Common Lisp, Emacs Lisp не предусматривает интернирование одного и того же имени в нескольких разных «пакетах», таким образом создавая несколько символов с одинаковым именем, но разными пакетами. Emacs Lisp предоставляет другую систему пространства имен, называемую «сокращениями» (см. Сокращения).
Эта функция создает и возвращает новый обаррей. Необязательный аргумент size может использоваться для указания количества символов, которое, как ожидается, будет содержаться, но поскольку обарреи автоматически растут по мере необходимости, это редко дает какое-либо преимущество.
Эта функция возвращает t, если object является обарреем,
и nil в противном случае.
Большинство функций, приведенных ниже, принимают имя и, иногда, обаррей в качестве
аргументов. Ошибка wrong-type-argument сигнализируется, если имя
не является строкой или если обаррей не является объектом обаррея.
Эта функция возвращает строку, которая является именем symbol. Например:
(symbol-name 'foo)
⇒ "foo"
Предупреждение: Никогда не изменяйте строку, возвращаемую этой функцией. Это может сделать Emacs нефункциональным и даже привести к аварийному завершению Emacs.
Создание неинтернированного символа полезно при генерации кода Lisp, потому что неинтернированный символ, используемый как переменная в генерируемом вами коде, не может конфликтовать с какими-либо переменными, используемыми в других программах на Lisp.
Эта функция возвращает новый выделенный неинтернированный символ, имя которого —
name (должно быть строкой). Его значение и определение функции
пусты, а список свойств равен nil. В приведенном ниже примере
значение sym не является eq к foo, потому что это
отдельный неинтернированный символ, имя которого также «foo».
(setq sym (make-symbol "foo"))
⇒ foo
(eq sym 'foo)
⇒ nil
Эта функция возвращает символ, используя make-symbol, имя которого
создается путем добавления gensym-counter к prefix и увеличения
этого счетчика, что гарантирует, что никакие два вызова этой функции не
сгенерируют символ с одинаковым именем. Префикс по умолчанию —
"g".
Чтобы избежать проблем при случайном интернировании печатного представления
сгенерированного кода (см. Печатное представление и синтаксис чтения), рекомендуется
использовать gensym вместо make-symbol.
Эта функция возвращает интернированный символ, имя которого — name. Если
в обаррее obarray нет такого символа, intern
создает новый, добавляет его в обаррей и возвращает его. Если
obarray опущен, используется значение глобальной переменной
obarray.
(setq sym (intern "foo"))
⇒ foo
(eq sym 'foo)
⇒ t
(setq sym1 (intern "foo" other-obarray))
⇒ foo
(eq sym1 'foo)
⇒ nil
Примечание Common Lisp: В Common Lisp вы можете интернировать существующий символ в обаррей. В Emacs Lisp вы не можете этого сделать, потому что аргумент для
internдолжен быть строкой, а не символом.
Эта функция возвращает символ в obarray, имя которого —
name, или nil, если obarray не имеет символа с таким именем.
Таким образом, вы можете использовать intern-soft для проверки, интернирован ли уже символ с
заданным именем. Если obarray опущен, используется
значение глобальной переменной obarray.
Аргумент name также может быть символом; в этом случае
функция возвращает name, если name интернирован
в указанном обаррее, и nil в противном случае.
(intern-soft "frazzle") ; Такого символа не существует. ⇒ nil (make-symbol "frazzle") ; Создать неинтернированный. ⇒ frazzle
(intern-soft "frazzle") ; Этот не может быть найден.
⇒ nil
(setq sym (intern "frazzle")) ; Создать интернированный.
⇒ frazzle
(intern-soft "frazzle") ; Этот можно найти!
⇒ frazzle
(eq sym 'frazzle) ; И это тот же самый.
⇒ t
Эта переменная является стандартным обарреем для использования intern и
read.
Эта функция вызывает function один раз для каждого символа в обаррее
obarray. Затем она возвращает nil. Если obarray
опущен, по умолчанию используется значение obarray — стандартный
обаррей для обычных символов.
(setq count 0)
⇒ 0
(defun count-syms (s)
(setq count (1+ count)))
⇒ count-syms
(mapatoms 'count-syms)
⇒ nil
count
⇒ 1871
См. documentation в Доступ к строкам документации для другого
примера использования mapatoms.
Эта функция удаляет symbol из обаррея obarray. Если
symbol на самом деле не находится в обаррее, unintern ничего
не делает. Если obarray равен nil, используется текущий обаррей.
Если вы передаете строку вместо символа в качестве symbol, она
обозначает имя символа. Тогда unintern удаляет символ (если есть) в
обаррее, который имеет это имя. Если такого символа нет,
unintern ничего не делает.
Если unintern действительно удаляет символ, он возвращает t. В противном случае
он возвращает nil.
Эта функция удаляет все символы из obarray.