Да, вам нужно получить f
откуда-то где-нибудь - ваш макрос просто создает это, и поэтому он не виден пользователям foo
. Когда вы считаете, что вам нужно его откуда-то получить, вопрос в том, откуда бы вы это взяли? Вот фиксированная версия вашего кода, в которой предполагается, что это первое, что есть во второй подчиненной форме foo
:
(define-syntax foo
(syntax-rules ()
[(_ l (f a) more ...)
(let-syntax ([f (syntax-rules ()
[(_ n) (l 'f n)])])
(list (f a) more ...))]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary) (f 3))
(Я также расширил его до list
, чтобы увидеть, что все формы преобразованы.)
Однако, если вы хотите, чтобы внутри foo
использовался глобальный вид f
, вам действительно нужно сделать именно это: определить глобальный f
. Вот ограниченный способ сделать это:
;; no body => using `f' is always an error
(define-syntax f (syntax-rules ()))
(define-syntax foo
(syntax-rules ()
[(_ l a ...) (list (foo-helper l a) ...)]))
(define-syntax foo-helper
(syntax-rules (f) ; match on f and transform it
[(_ l (f n)) (l 'f n)]
[(_ l a) a]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary) (f 3))
Основное ограничение в том, что это будет работать, только если одна из a
форм использует f
, но не будет работать, если она вложена в выражение. Например, это вызовет синтаксическую ошибку:
(foo x (f 1) (f 2) (arbitrary)
(let ([n 3]) (f n)))
Вы можете представить себе усложнение foo-helper
и заставить его рекурсивно сканировать входные данные, но это скользкая дорожка, на которую вы не хотите попасть. (Вам нужно будет сделать особые случаи для таких мест, как внутри quote
, в привязке и т. Д.)
Чтобы решить эту проблему в Racket (а в последнее время и в Guile), используйте параметр синтаксиса < / а>. Подумайте об этом как о привязке f
к тому же бесполезному макросу с помощью _ 16_, а затем используйте _ 17_ для" корректировки "его значения внутри foo
макроса это делает преобразование, которое вы хотите. Вот как это выглядит:
;; needed to get syntax parameters
(require racket/stxparam)
;; same useless definition, but as a syntax parameter
(define-syntax-parameter f (syntax-rules ()))
(define-syntax foo
(syntax-rules ()
[(_ l a ...)
;; adjust it inside these forms
(syntax-parameterize ([f (syntax-rules ()
[(_ n) (l 'f n)])])
(list a ...))]))
(define (x t1 t2) (cons t1 t2))
(define (arbitrary) (cons 'a 'b))
(foo x (f 1) (f 2) (arbitrary)
(let ([n 3]) (f n)))
person
Eli Barzilay
schedule
24.01.2012