1

拡大したい

(foo x (f n) (f n) (arbitrary) (f n) ...)

の中へ

(begin (x 'f n) (x 'f n) (arbitrary) (x 'f n) ...)

私の試みは:

(define-syntax foo
  (syntax-rules ()
    ((_ l a ...)
     (let-syntax ((f (syntax-rules ()
                       ((_ n) (l (quote f) n)))))
       (begin a ...)))))

(define (x t1 t2) (cons t1 t2))   ;; for example only
(define (arbitrary) (cons 'a 'b)) ;; for example only
(foo x (f 1) (f 2) (arbitrary) (f 3))

マクロステッパーを使用すると、マクロの最初のステージが次のように展開されることがわかります。

(let-syntax ((f (syntax-rules () ((_ n) (x 'f n)))))
  (begin (f 1) (f 2) (arbitrary) (f 3)))

これは、単独で評価すると完全に機能しますが、全体として実行するとf、未定義の識別子であるというエラーが発生します。これはスコープの問題だと思いますが、このタイプのマクロ展開は可能ですか?

4

1 に答える 1

3

ええ、どこかfから取得する必要があります-マクロはそれを構成するだけなので、のユーザーには表示されません。どこかから入手する必要があると考えるとき、問題はどこから入手するかです。これが の 2 番目のサブフォームの最初のものであると仮定した修正版のコードです。foofoo

(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)))
于 2012-01-24T14:23:46.227 に答える