マクロの書き方が分かりかけてきた

初めは本とかの、例文を修正程度しか分からなかったけど、構文を作ると言う意味がやっと理解できてきた。


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とかはまだ理解していないので後回し。