Common LispのパターンマッチングライブラリLitMatchを作りました
バイトで書いているコードでパターンマッチが必要になりちょっと探してみたのですが、自分が使いやすいものが無かったので適当に作りました。Literal Match の略で LitMatch です。
http://github.com/hayamiz/LitMatch
やりたいことはそんなに複雑ではなくて、木構造データが特定の形をしているかどうかを調べつつ、マッチした木構造の特定のサブツリーを抜き出したいというもの。ML系言語でよく見られるあれですね。絶対どこかに似たようなものがあるはず、、、と思いつつ探すより作ったほうが早かったので作りました。こうして車輪で世界は埋め尽くされるのだなあ。
使い方としては、LitMatchという名前のとおり極力リテラルをそのまんま書けることを目指しています。たとえば
(litmatch '(1 (2 "hello" world 3)) ((1 (2 "hello" world 3)) "match!") (t "unmatch")) ;; => "match!"
みたいな感じです。では、サブツリーの値を取り出すときにはどうするかというと
(litmatch '(1 (2 "hello" world 3)) ((1 (2 v%foo world 3)) foo) (t "unmatch")) ;; => "hello"
のように v%<束縛するシンボル名> というシンボルを置いてあげることで束縛します。「この例だと、'v%foo というシンボル自体が含まれているかどうかマッチングできないじゃないか」と思うかもしれませんが、それは正しいです。これは実装上の手抜きですが、v%%foo は v%foo というシンボルとみなす、みたいな回避方法はとれるので本質的にはそんな問題にはならないでしょう。
あともう一つ
(litmatch '(1 (2 "hello" world 3)) ((1 ((2 v%hoge world 3) . as%piyo)) `(:hoge ,hoge :piyo ,piyo)) (t "unmatch")) ;; => (:hoge "hello" :piyo (2 "hello" world 3))
のように値を束縛することもできます。サブツリーの中身に関してもマッチングした上で、サブツリー全体を束縛したいという用途向けですね。Gaucheのmatchでこれ相当のことをやる方法が未だにわかっていないんだけど、どうやるんだろう*1。
最近はプライベートでLisp系言語をつかって遊ぶ余裕が無くてカッコッカ力が低下しているのを感じますね。隙あらばLispという心掛けを忘れないようにしたいです。
*1:と書いておくとshiroさんがやってきて教えてくれるはず、、、