Суффикс .0
на самом деле не является суффиксом имени сгенерированной привязки - он указывает, что идентификатор был введен макросом и находится внутри области действия макроса.Основная проблема заключается в том, что вы используете format-id
.
. Помните, что макросистема Racket гигиеническая .Это означает, что привязки, введенные макросами, могут быть видны только макросами.Это делает автозаполнение в REPL немного более сложным, и я не думаю, что REPL делает здесь, честно говоря, очень полезный выбор.Тем не менее, вы, вероятно, хотите знать, как исправить свой код, а не тонкости того, почему REPL показывает введенные макросы привязки с суффиксом .0
.
Когда вы вызываете format-id
, получаетсяидентификатор будет иметь тот же лексический контекст, что и первый аргумент.Вы можете думать об этом как о значении того, что созданный идентификатор будет жить в той же лексической области, что и этот фрагмент синтаксиса.В вашем случае вы предоставляете stx
, который представляет всю форму ввода для макроса.
При непосредственном использовании iex-op
, например, путем записи (iex-op quote)
, затем идентификатора quote
происходит из той же лексической области, что и форма (iex-op ....)
.Поэтому, когда вы вызываете format-id
и даете ей форму (iex-op ....)
в качестве первого аргумента, вы все равно получаете идентификатор, который разделяет ту же лексическую область, что и идентификатор quote
, и все в порядке.
Однако , когда вы используете макрос iex-op*
, он пропускает синтаксический объект op0
, но окружающая форма (iex-op ....)
приходит из макроса iex-op*
.Это означает, что stx
теперь относится к области видимости внутри макроса iex-op*
, не к области действия идентификатора op0
.Чтобы исправить это, измените ваш вызов на format-id
, чтобы он создавал идентификатор с той же областью, что и идентификатор операции, а не окружающий объект синтаксиса:
(format-id #'oper "iex-~a" #'oper)
Теперь ваш макрос будет работать так, как задумано.
Перед тем, как закончить, спросите себя: какие здесь есть вынос?Вот пара:
Нарушение гигиены является тонким.Когда вы решите написать негигиеничный макрос (а format-id
негигиеничен), очень задумайтесь над тем, откуда вы получаете лексический контекст.Подумайте, что произойдет, когда пользователи напишут макросы поверх вашего макроса.
В этом случае вам повезло, что вы являетесь автором iex-op
и iex-op*
, поэтому вы можете исправить iex-op
после того, как выстолкнулся с проблемой с ним.Но если бы вы не были автором iex-op
, только iex-op*
, вы оказались бы в гораздо более сложной ситуации.Подумайте об этом всякий раз, когда вы пишете какой-либо негигиеничный макрос, чтобы избежать подобных проблем в будущем.
Как правило, при негигиенической обработке нового идентификатора из другого идентификатора лучше всего использоватьэтот другой идентификатор как источник лексического контекста.Таким образом, лексическая область действия идентификатора, предоставленного пользователем, будет сохранена, чего ожидают пользователи.
Возможно, некоторые примеры в Fear of Macros, которые используют format-id
,небрежно в этом отношении.Возможно, стоит попытаться улучшить их, чтобы показать лучший пример.