Subscribed unsubscribe Subscribe Subscribe

util.matchでパターンマッチ

Gauche

最近define-macroでごちゃごちゃS式をいじることを試しています。
渡された引数をお手軽に処理してみたくて、util.matchを使ってみようとした。

(region
  (width 210mm)
  (height 297mm))
...中略
(make <region> :width 210 :height 297)

やりたいことは上記みたいに展開してみること。
ミニ言語とか埋め込み言語とか言ったりするものなのかな。

(define func
  (match-lambda
    (((key val) ...)
     (format "key=~s val=~s" key val))
    (_
     (format "error"))))

まずはkeyとvalの繰り返しにマッチさせることを考えてみた。
以下のような感じでkeyとvalにマッチさせることができます。

(func '((a b) (c d) (e f)))
=>gosh> "key=(a c e) val=(b d f)"

これができれば、keyのそれぞれにmake-keywordを適用してスロットの初期化指定のリストに変換してやれば
インスタンスを(regionを記述するだけで生成させるようなS式に変換できる。

(func '((a b) (c d) (e (f g)) (h i)))
=>gosh> "key=(a c e h) val=(b d (f g) i)"

この定義ならkey eに対応するvalがリスト(f g)でも良い。

(func '((a b) (c d) (e (f g) (h i))))
=>gosh> "error"

けれども、valが(f g) (h i)のような場合に失敗してしまう。
例えば、(page 以降の部分にマッチさせようとしても、errorになる。

(page (width 210) (height 297) (region (width 210) (height 297)))

さて、こういうときはパターンをどう記述するのがいいんだろうか。

(define func
  (match-lambda
    ((key ((key2 val2) ...))
     (format "key=~s key2=~s val2=~s" key key2 val2))
    (((key val) ...)
     (format "key=~s val=~s" key val))
    (_
     (format "error"))))

とすればいいのかと思ったけど違うらしい。