Различия между Sharpsign Colon и Gensym
Я только что читал о макросе читателя двоеточия Sharpsign, и это звучало так, как будто он очень похож на gensym
Sharpsign Colon: "вводит непереданный символ"
Генсим: "Создает и возвращает свежий, не имеющий отношения символ"
Итак, простой тест
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {1002FF77D3}>.
CL-USER> (defparameter #:dave 1)
#:DAVE
CL-USER> #:dave
; Evaluation aborted on #<UNBOUND-VARIABLE DAVE {100324B493}>.
Круто, так что не получается как надо.
Теперь для макро-теста
(defmacro test (x)
(let ((blah '#:jim))
`(let ((,blah ,x))
(print ,blah))))
CL-USER> (test 10)
10
10
CL-USER>
Сладкий, так что его можно использовать как в родном стиле.
Для меня это выглядит чище, чем gensym с явно идентичным результатом. Я уверен, что мне не хватает важной детали, поэтому мой вопрос, что это такое?
2 ответа
GENSYM
как MAKE-SYMBOL
, Разница в том, что GENSYM
поддерживает причудливое именование путем подсчета ->, таким образом, символы имеют уникальные имена, что облегчает отладку при использовании gensyms, например, в расширениях макросов.
#:foo
это обозначение для читателя.
Таким образом, у вас есть функция, которая создает их и буквальное обозначение. Обратите внимание, что когда *print-circle*
правда, некоторая идентичность может быть сохранена в s-выражениях: #(#1=#:FOO #1#)
,
Вообще это похоже на (a . b)
а также (cons 'a 'b)
, #(a b)
а также (vector 'a 'b)
... Один - это буквальные данные, а другой - форма, которая будет создавать ("минусы") свежие объекты.
Если вы посмотрите на свой макрос, основная проблема заключается в том, что его использование может вызвать проблемы. Оба лексически или динамически.
Лексически это может быть та же переменная, что и отскок.
динамически, если это специальная переменная, она также может быть отскок
Использование сгенерированного символа во время раскрытия макроса гарантирует, что другой и расширенный код не будет совместно использовать привязки.
Каждый раз, когда макрос раскрывается, он будет использовать один и тот же символ.
(defmacro foo () `(quote #:x))
(defmacro bar () `(quote ,(gensym)))
(eq (foo) (foo)) => t
(eq (bar) (bar)) => nil
Gensym будет создавать новый символ каждый раз, когда он оценивается, но острый двоеточие будет создавать новый символ только тогда, когда он прочитан.
Хотя использование острого толстого кишечника вряд ли вызовет проблемы, есть пара редких случаев, когда его использование почти невозможно обнаружить ошибки. Лучше быть безопасным для начала, всегда используя gensym.
Если вы хотите использовать что-то вроде острого двоеточия, вы должны посмотреть на defmacro! макрос из Let Over Lambda.