Spec-Zone.ru › Elisp

Создание и интернирование символов

Чтобы понять, как символы создаются в GNU Emacs Lisp, необходимо знать, как Lisp их считывает. Lisp должен гарантировать, что каждый раз при чтении той же последовательности символов в том же контексте он находит один и тот же символ. В противном случае это приведет к полной путанице.

Когда читатель Lisp встречает имя, ссылающееся на символ в исходном коде, он считывает все символы этого имени. Затем он ищет это имя в таблице, называемой obarray, чтобы найти символ, который имел в виду программист. Метод, используемый в этом поиске, называется «хешированием», эффективным методом поиска, при котором последовательность символов преобразуется в число, называемое «хеш-кодом». Например, вместо того, чтобы искать в телефонной книге от начала до конца при поиске Яны Джонс, вы начинаете с буквы «Я» и переходите оттуда. Это простая версия хеширования. Каждый элемент obarray — это ведро, которое содержит все символы с заданным хеш-кодом; чтобы найти заданное имя, достаточно перебрать все символы в ведре с хеш-кодом этого имени. (Такой же принцип используется для общих хеш-таблиц Emacs, но они представляют собой другой тип данных; см. Хеш-таблицы.)

При поиске имен читатель Lisp также учитывает «псевдонимы». Если программист их предоставил, это позволяет читателю найти символ, даже если его имя не присутствует в полном виде в исходном коде. Конечно, читателю нужна информация о таких псевдонимах, точно так же, как нам нужен контекст, чтобы однозначно указать на Яну Джонс, используя только имя «Яна»: это, вероятно, приемлемо среди Джонсов или когда Яна упоминалась недавно, но очень неоднозначно в любой другой ситуации. См. Псевдонимы.

Если символ с нужным именем найден, читатель использует этот символ. Если в obarray нет символа с этим именем, читатель создает новый символ и добавляет его в obarray. Поиск или добавление символа с определенным именем называется его интернированием, а сам символ называется интернированным символом.

Интернирование гарантирует, что в каждом obarray существует только один символ с любым конкретным именем. Другие символы с таким же именем могут существовать, но не в одном и том же obarray. Таким образом, читатель получает те же символы для тех же имен, если вы продолжаете чтение с тем же obarray.

Интернирование обычно происходит автоматически в процессе чтения, но иногда другие программы могут захотеть выполнить его. Например, после выполнения команды M-x программа получает имя команды в виде строки с помощью мини-буфера, а затем интернирует эту строку, чтобы получить интернированный символ с этим именем. Еще один пример — гипотетическая программа телефонной книги, которая могла бы интернировать имя каждого найденного человека в виде символа, даже если его нет в obarray, чтобы прикрепить к этому новому символу информацию, например, о последнем времени поиска.

Ни один obarray не содержит все символы; на самом деле, некоторые символы не находятся ни в одном obarray. Они называются неинтернированными символами. Неинтернированный символ имеет те же четыре ячейки, что и другие символы; однако единственный способ получить к нему доступ — найти его в каком-то другом объекте или как значение переменной. Неинтернированные символы иногда полезны при генерации кода Lisp, см. ниже.

В Emacs Lisp obarray фактически является вектором. Каждый элемент вектора — это ведро; его значение — либо интернированный символ, имя которого хешируется в это ведро, либо 0, если ведро пусто. Каждый интернированный символ имеет внутреннюю ссылку (невидимую для пользователя) на следующий символ в ведре. Поскольку эти ссылки невидимы, нет способа найти все символы в obarray, кроме как используя mapatoms (ниже). Порядок символов в ведре не имеет значения.

В пустом obarray каждый элемент равен 0, поэтому вы можете создать obarray с помощью (make-vector length 0). Это единственный допустимый способ создания obarray. Простые числа в качестве длин обычно приводят к хорошему хешированию; длины, на единицу меньшие степени двойки, также хороши.

Не пытайтесь добавлять символы в obarray самостоятельно. Это не работает — только intern может правильно добавить символ в obarray.

Примечание по Common Lisp: В отличие от Common Lisp, Emacs Lisp не предоставляет возможность интернирования одного и того же имени в нескольких разных «пакетах», тем самым создавая несколько символов с одинаковым именем, но разными пакетами. Emacs Lisp предоставляет другую систему именования, называемую «псевдонимами» (см. Псевдонимы).

Большинство функций ниже принимают имя и иногда obarray в качестве аргументов. Ошибка wrong-type-argument возникает, если имя не является строкой или если obarray не является вектором.

Функция: symbol-name символ

Эта функция возвращает строку, которая является именем символ. Например:

(symbol-name 'foo)
     ⇒ "foo"

Предупреждение: Изменение строки путем замены символов изменяет имя символа, но не обновляет obarray, поэтому не делайте этого!

Создание неинтернированного символа полезно при генерации кода Lisp, потому что неинтернированный символ, используемый в качестве переменной в генерируемом коде, не может конфликтовать с переменными, используемыми в других программах Lisp.

Функция: make-symbol имя

Эта функция возвращает недавно выделенный неинтернированный символ, имя которого имя (должно быть строкой). Его значение и определение функции не определены, а список свойств — nil. В приведенном ниже примере значение sym не равно eq до foo, потому что это отдельный неинтернированный символ, имя которого также ‘foo’.

(setq sym (make-symbol "foo"))
     ⇒ foo
(eq sym 'foo)
     ⇒ nil
Функция: gensym &optional префикс

Эта функция возвращает символ, используя make-symbol, имя которого создается путем добавления gensym-counter к префикс и увеличения этого счётчика, гарантируя, что два вызова этой функции не сгенерируют символ с одинаковым именем. Префикс по умолчанию "g".

Для предотвращения проблем при случайном интернировании печатного представления сгенерированного кода (см. Печатное представление) рекомендуется использовать gensym вместо make-symbol.

Функция: intern имя &optional obarray

Эта функция возвращает интернированный символ, имя которого имя. Если такого символа нет в obarray obarray, intern создает новый, добавляет его в obarray и возвращает его. Если 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 вы можете интернировать существующий символ в obarray. В Emacs Lisp это невозможно, потому что аргумент функции intern должен быть строкой, а не символом.

Функция: intern-soft имя &optional obarray

Эта функция возвращает символ в obarray, имя которого имя, или nil, если в obarray нет символа с этим именем. Поэтому вы можете использовать intern-soft для проверки, уже ли интернирован символ с данным именем. Если obarray опущен, используется значение глобальной переменной obarray.

Аргумент имя также может быть символом; в этом случае функция возвращает имя, если имя интернировано в указанном obarray, и в противном случае nil.

(intern-soft "frazzle")        ; No such symbol exists.
     ⇒ nil
(make-symbol "frazzle")        ; Create an uninterned one.
     ⇒ frazzle
(intern-soft "frazzle")        ; That one cannot be found.
     ⇒ nil
(setq sym (intern "frazzle"))  ; Create an interned one.
     ⇒ frazzle
(intern-soft "frazzle")        ; That one can be found!
     ⇒ frazzle
(eq sym 'frazzle)              ; And it is the same one.
     ⇒ t
Переменная: obarray

Эта переменная является стандартным obarray для использования функциями intern и read.

Функция: mapatoms функция &optional obarray

Эта функция вызывает функция один раз с каждым символом в obarray obarray. Затем она возвращает nil. Если obarray опущен, по умолчанию используется значение obarray, стандартный obarray для обычных символов.

(setq count 0)
     ⇒ 0
(defun count-syms (s)
  (setq count (1+ count)))
     ⇒ count-syms
(mapatoms 'count-syms)
     ⇒ nil
count
     ⇒ 1871

См. documentation в Доступе к документации для другого примера использования mapatoms.

Функция: unintern символ obarray

Эта функция удаляет символ из obarray obarray. Если символ фактически не содержится в obarray, unintern ничего не делает. Если obarray равен nil, используется текущий obarray.

Если вы предоставляете строку вместо символа в качестве символ, она представляет имя символа. Затем unintern удаляет символ (если таковой имеется) в obarray, имеющий это имя. Если такого символа нет, unintern ничего не делает.

Если unintern удаляет символ, он возвращает t. В противном случае он возвращает nil.

Copyright © 1990-1996, 1998-2022 Free Software Foundation, Inc.
Licensed under the GNU GPL license.
https://www.gnu.org/software/emacs/manual/html_node/elisp/Creating-Symbols.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API