Обычно я очень осторожно добавляю скобки в Racket.
Да, будьте осторожны. Обычно это имеет значение.
В вашем случае, однако, это не имеет значения, потому что вы создаете слишком простой макрос, который расширяется таким же образом, независимо от того, вызывается ли макрос как обычный преобразователь или как макрос идентификатора.
Я ожидал чего-то вроде # процедуры для первого вызова foo.
Я хочу сначала коснуться этого. Макросы синтаксически преобразуют вашу программу. Например, я могу написать макрос flip
, который переворачивает операнды, чтобы
(flip foo 1 (let) bar baz 2)
расширяется (не оценивается) до:
(2 baz bar (let) 1 foo)
Опять же, я хочу подчеркнуть, что это преобразование программы, подобное тому, как вы редактируете код с помощью своего редактора.
Теперь давайте напишем несколько реальных макросов:
(define-syntax bar
(lambda (stx)
(cond
[(equal? (syntax->datum stx) '(bar abc def)) #'(+ 1 1)]
[else #'(+ 2 2)])))
(bar abc def) ;== expands => (+ 1 1) == evaluates => 2
(bar 42 (abc) qqq) ;== expands => (+ 2 2) == evaluates => 4
(bar) ;== expands => (+ 2 2) == evaluates => 4
В приведенном выше макросе он проверяет, является ли синтаксис ввода синтаксически (bar abc def)
. Если это так, он преобразуется в (+ 1 1)
. В противном случае он преобразуется в (+ 2 2)
.
Все это должно показать вам, что неразумно ожидать, что макрос приведет к #procedure (конечно, если макрос не расширяется до лямбда), поскольку макрос преобразует синтаксис. Это не создает процедуры.
Последняя загадка - что происходит с голым foo
. Давайте создадим макрос baz
, чтобы понять, что:
(define-syntax baz
(lambda (stx)
(cond
[(equal? (syntax->datum stx) 'baz) #'1]
[(equal? (syntax->datum stx) '(baz)) #'2]
[else #'3])))
baz ;== expands => 1
(baz) ;== expands => 2
(baz 10) ;== expands => 3
Оказывается, простой идентификатор также может быть макросом!
Теперь рассмотрим свой foo
:
(define-syntax foo
(lambda (stx)
(syntax "I am foo")))
Это преобразование, которое игнорирует свои операнды и всегда расширяется до "I am foo"
.
So:
(foo 1 2 3) ;== expands => "I am foo"
(foo x y z) ;== expands => "I am foo"
(foo) ;== expands => "I am foo"
foo ;== expands => "I am foo"
Обратите внимание, что в большинстве макросов мы используем сопоставление с образцом для извлечения операндов. Сопоставление с шаблоном может вызвать синтаксическую ошибку, если синтаксис ввода не соответствует ни одному шаблону. Это, например, позволяет нам создать макрос, который не позволяет использовать его в качестве макроса идентификатора.
(define-syntax food
(lambda (stx)
(syntax-case stx ()
;; match when there is a parenthesis around the macro
[(_ ...) #'1])))
(food) ;=> 1
food ;=> food: bad syntax
person
Sorawee Porncharoenwase
schedule
20.03.2021