Как создать: ключевые слова?

16

Q: Как создать и использовать :keywords?

Рассмотрим (наивно, по-видимому) попытку доступа к следующему списку игрушек:

(setf alist '((:key-1 "Key no. 1")
              (:key-2 "Key no. 2")))

(assq :key-1 alist)                 ; => (:key-1 "Key no. 1")
(assq (make-symbol ":key-1") alist) ; => nil

Первый ключ работает как положено, а второй - нет. Поскольку нет очевидной make-keywordфункции, как можно создать и использовать ключевое слово?

Первоначальная мотивация: мне нужно преобразовать строку в ключ поиска, который является символом, для которого я могу putсвойства.

В процессе формулирования этого вопроса я получил хотя бы часть ответа, который я публикую отдельно. Я надеюсь, что более яркие умы, чем мои, могут улучшить это.

Дэн
источник
1
(eq :foo (read ":foo"))
abo-abo

Ответы:

9

Вы правы, что make-symbolсоздадите ключевое слово, которое не относится eqк какому-либо существующему ключевому слову, и internможет загрязнить глобальное пространство новым символом. Между ними у вас есть intern-soft, который возвращает символ, если он уже был создан, или nilесли он не был:

ELISP> (intern-soft ":key-1")
nil
ELISP> :key-1
:key-1
ELISP> (intern-soft ":key-1")
:key-1

Это должно подходить для вашей цели: если ключевое слово не существует, оно не может присутствовать в alist, поэтому нет необходимости создавать его просто для проверки его наличия. Что-то вроде:

(let ((maybe-keyword (intern-soft ":key-1")))
  (and maybe-keyword (assq maybe-keyword alist)))
legoscia
источник
Умно - я видел, intern-softно не думал использовать это таким образом.
Дан
6

Возможно, я не правильно понимаю вопрос. Но если вы хотите ключевое слово (то есть, вы хотите удовлетворить keywordp) , то вы хотите , чтобы символ интернирован в глобальной obarray , obarray.

Это должно быть интернировано там, чтобы удовлетворить keywordp, AFAICT, и C-h f keywordpтак говорит.

Таким образом, ответ на ваш вопрос, AFAICT, просто использоватьintern .

Я чувствую, что вы, возможно, не задаете свой настоящий вопрос - кажется, вопрос XY. Что ты на самом деле пытаешься сделать? (Возможно поставьте это как отдельный вопрос.)

[В ответ на ваш комментарий, что интернирование « не является :keywordспецифическим, поскольку оно применяется ко всем символам »: правильно, интернирование не является специфическим для ключевых слов. Но интернирование (в obarray) и использование, symbol-nameкоторое начинается с :, специфично для ключевых слов.]

Нарисовалась
источник
Это, безусловно, вопрос XY в том смысле, что я пытаюсь ответить на вопрос Y, но я действительно заинтересовался X, пытаясь добраться до Y. Позвольте мне немного подумать о том, как поставить вопрос о Y таким образом, чтобы полезно и для других.
Дан
Отлично. Это будет полезно. Спасибо.
Дрю
2

Вот частичный ответ на этот вопрос. Короткая и не совсем удовлетворительная версия выглядит так: use intern.

:key-1 удовлетворяет как:

(symbolp :key-1)                    ; => t
(keywordp :key-1)                   ; => t

Пока (make-symbol ":key-1")удовлетворяет первое, но не второе

(symbolp (make-symbol ":key-1"))    ; => t
(keywordp (make-symbol ":key-1"))   ; => nil

Теперь, строка документации make-symbolговорит, что это будет:

Вернуть недавно выделенный неустранимый символ с именем NAME.

Mmmkay, и документация для keywordpговорит, что это будет:

Вернуть, tесли OBJECT является ключевым словом. Это означает, что это символ с именем печати, начинающимся с : интернированного в исходном массиве.

Похоже, что internбудет работать:

(assq (intern ":key-1") alist)      ; => (:key-1 "Key no. 1")

Потому что internбудет:

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

Но это не кажется :keywordконкретным, поскольку это относится ко всем символам. По умолчанию, это также, кажется, загрязняет глобальный obarray, который может или не может быть Большой Курс.

Дэн
источник