QA@IT

Gauche の util.match で効率よく木をマッチさせるには?

3136 PV

Gauche の util.match をつかって、次のような簡単な木のパターンマッチをしたいと考えています。

(define ex1 '((1 "two") ("three" 4)))
(define ex2 '(("one" 2) (3 "four")))

ここで、木は 2 つのリストからなり、それぞれのリストは文字列と数値が、1 個づつ順不同で格納されているとします。
文字列と数値のどちらが先にくるかで、全部で 4 通りの場合があるので、ひとつの match をつかって次のような関数を書きました:

(define (match-tree-naive t)
  (match t
         ((((? number? n1) (? string? str1))
           ((? number? n2) (? string? str2)))
          (print (list "number" n1 n2))
          (print (list "string" str1 str2)))

         ((((? number? n1) (? string? str1))
           ((? string? str2) (? number? n2)))
          (print (list "number" n1 n2))
          (print (list "string" str1 str2)))

         ((((? string? str1) (? number? n1))
           ((? number? n2) (? string? str2)))
          (print (list "number" n1 n2))
          (print (list "string" str1 str2)))

         ((((? string? str1) (? number? n1))
           ((? string? str2) (? number? n2)))
          (print (list "number" n1 n2))
          (print (list "string" str1 str2)))

         ))

しかしこれはあまりにも冗長で拡張性もないので、複数の match を組み合わせて再帰的に、以下のように書いてみました。

(define (match-tree t)
  (define (match-tip p)
    (match p
           ((? number? n)
            (print (list "number" n)))
           ((? string? str)
            (print (list "number" str)))))

  (define (match-part p)
    (match p
           ((tips ...)
            (for-each match-tip tips))))

  (match t
         ((part ...)
          (for-each match-part part))))

これで、リストの要素の数などには柔軟に対応できますが、何となく処理が行ったり来たりしてコードが分かりづらいです。

できれば match をたくさん使わずに、このような構造で簡単にパターンマッチする方法はないでしょうか?

回答

残念ながら、この目的にそのまま使えるライブラリというのはすぐには思い当たらないです。

この例のような、順不同でマッチをかけたり、「リストにいくつか要素があるうちこういうのにマッチするのが確かに含まれていることを調べたい」、といった用途に使えるようなマッチャは以前書いたことがあります。テストで、生成されるXMLが特定の条件に合っているかどうか調べるものです。

https://github.com/kahua/Kahua/blob/master/src/kahua/test/xml.scm

もう少しうまく汎用化してライブラリとして取り込めれば良いのですが。

編集 履歴 (0)
  • なるほどー。ありがとうございます。そうそう、XML でこういう順不同だったり抜けがあったりするような構造をうまく扱えないかと思って質問しました。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。