ええ、どこかf
から取得する必要があります-マクロはそれを構成するだけなので、のユーザーには表示されません。どこかから入手する必要があると考えるとき、問題はどこから入手するかです。これが の 2 番目のサブフォームの最初のものであると仮定した修正版のコードです。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
(また、すべてのフォームが変換されることを確認するために、 に展開しました。)
ただし、グローバルな種類のf
を内部foo
で使用したい場合は、実際にそれを行う必要があります: グローバルを定義します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
フォームの 1 つが使用されている場合にのみ機能f
することですが、式にネストされている場合は機能しません。たとえば、これは構文エラーをスローします。
(foo x (f 1) (f 2) (arbitrary)
(let ([n 3]) (f n)))
複雑にして、入力を再帰的にスキャンさせることは想像できますがfoo-helper
、それは滑りやすい坂道であり、入りたくないものです。quote
( の内部、バインディングなどの場所については、特別なケースを作成する必要があります。)
これを Racket (最近では Guile でも) で解決する方法は、構文パラメーターを使用することです。f
これは、を使用して同じ役に立たないマクロにバインドし、define-syntax-parameter
を使用して、必要な変換を行うマクロにsyntax-parameterize
その意味を「調整」するものと考えてください。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)))