RacketのMacroを調べてみる (6)
ここらから少し応用編
適当に端折っていきます
ちゃんとしくみを理解してないと、の方針は続いていて、エラーを出したり
それを調べたりしながら順を追って関数名を作る話をしてくれます
- syntaxの内側でないとpattern variableは参照できない
- template内はpattern variable以外置き換えは起こらない
- 置き換えたければsyntax-caseを入れ子にして使うことができる
- マクロがうまく動かなくてどう展開されているのか知りたいときはMacro Stepperが便利
ここでいったんなんとか動くソース
(define-syntax (hyphen-define/ok1 stx)
(syntax-case stx ()
[(_ a b (args ...) body0 body ...)
(syntax-case (datum->syntax stx
(string->symbol (format "~a-~a"
(syntax->datum #'a)
(syntax->datum #'b))))
()
[name #'(define (name args ...)
body0 body ...)])]))
(hyphen-define/ok1 foo bar () #t)
を評価すると(define (foo-bar) #t)
になります
stx
に#'(hyphen-define/ok1 foo bar () #t)
が入るa
はfoo
、b
はbar
、(args ...)
は()
、body ...
は#t
にマッチする(syntax->datum #'a)
でfoo
を、(syntax->datum #'b)
でbar
を取り出すformat
で"foo-bar"
を作るstring->symbol
でfoo-bar
を作るdatum-syntax
で#'foo-bar
を作る- 内側の
syntax-case
でname
が#'foo-bar
にマッチする #'(define (name ...
が(define (foo-bar) #t)
に変換される
てことをしてます
死にそうです
こういうよくある(はず)の処理は簡単にできるようになってるはず
ふたつのツールが使えます
(syntax-case <syntax> () [<pattern> <body>])
の代わりに(with-syntax ([<pattern> <syntax>]) <body>)
が使えます(datum->syntax stx (string->symbol (format ... (syntax->datum #'a))))
の代わりに(format-id stx ... a)
が使えます
こうなりました
(define-syntax (hyphen-define/ok3 stx)
(syntax-case stx ()
[(_ a b (args ...) body0 body ...)
(with-syntax ([name (format-id stx "~a-~a" #'a #'b)])
#'(define (name args ...)
body0 body ...))]))
これなら生きていけます