В шаблоне syntax-case
идентификатор соответствует чему угодно. Вы уже предполагаете, что это правда: когда вы пишете шаблон (if a b)
, предположительно вы предполагаете, что a
будет соответствовать любому фрагменту синтаксиса, а не только литеральному идентификатору a
. То же самое верно для идентификатора if
- вы фактически не проверяете, что идентификатор равен if
, вы просто сопоставляете любой фрагмент синтаксиса и привязываете его к переменной шаблона с именем if
.
Для этого предназначен список литералов. Когда вы помещаете идентификатор в список литералов, он говорит syntax-case
проверить этот конкретный идентификатор вместо привязки переменной шаблона. Таким образом, вы, вероятно, хотите это вместо:
(define-syntax (foo stx)
(syntax-case stx (if cond)
[(_ (if a b)) #'"if!"]
[(_ (cond a b) #'"cond!"]))
Тем не менее, обратите внимание, что syntax-case
довольно старый, и Racket уже более десяти лет поставляется с лучшей библиотекой сопоставления синтаксиса, syntax/parse
. Я бы порекомендовал его выше syntax-case
во всех ситуациях. syntax/parse
эквивалент вышеупомянутого макроса выглядит следующим образом:
(require (for-syntax syntax/parse))
(define-syntax (foo stx)
(syntax-parse stx
#:literals [if cond]
[(_ (if a b)) #'"if!"]
[(_ (cond a b) #'"cond!"]))
… что в основном то же самое, но язык шаблонов syntax-parse
гораздо богаче, чем язык syntax-case
. Например, если вы хотите опустить объявление #:literals
, вы можете аннотировать отдельные литеральные шаблоны, используя ~literal
:
(define-syntax (foo stx)
(syntax-parse stx
[(_ ((~literal if) a b)) #'"if!"]
[(_ ((~literal cond) a b) #'"cond!"]))
Для получения дополнительной информации, см. Документацию для syntax/parse
.