マクロの書き方が分かりかけてきた
初めは本とかの、例文を修正程度しか分からなかったけど、構文を作ると言う意味がやっと理解できてきた。
Gauche本ではこんな風に書いてある。
(define-syntax 名前 (syntax-rules (リテラル) (<パターン> <テンプレート>) ))
リテラルはelseとかに係わるらしいけどまだ良く分からない。
http://www.shido.info/lisp/scheme_syntax.htmlにはこんな例がある。
(define-syntax nil! (syntax-rules () ((_ x) (set! x '()))))
良く分からなかったのはパターンとテンプレートを自分なりに使いこなせなかった。
例えば文字列を改行で、つなげるstring-lineをマクロで書いてみるとこうなる。
けどこれだったら普通に関数で作っても十分。
(define-syntax string-line (syntax-rules () ((_ str ...) (string-join '(str ...) "\n"))))
そうじゃなくて構文を作れる。
かなり強引な例だが、これはエラー番号、エラーメッセージとその他文字列をフォーマット化した文字列に変換するマクロ。
(define-syntax error-message (syntax-rules () ((_ ((errno message) str ...)) (string-append "[" (number->string errno) ":" message "]" str ...))))
これを実行してやる。
(print (error-message ((9 "SIGSEGV") "バグが発生"))) [9:SIGSEGV]バグが発生
このerror-messageの引数部分の書き方は関数では作れない。
今回のだと自前でcar,cdrとかしてやれば解析はできるけど本質はそうじゃない。
(error-message ((9 "SIGSEGV") "バグが発生"))
マクロの3行目を見ると、この部分がそのまま文法になっている。
((_ ((errno message) str ...))
つまり、単純な関数では(関数名 引数 ...)の形しか作れないけどマクロはこれを自由にできる。
当然Lisp/Schemeの処理系依存部分で移行できない部分もマクロをちょっと作れば、処理系依存部文を修正しなくても使えるようになる、等の処理が作れると。
今まで理解が出来なかったのは、関数の延長上で考えていたから。マクロは、文法その物を書いていく。
あと、define-macroとかはまだ理解していないので後回し。