まあ慣れかもしれないが,Common Lispで文字列をキーとした辞書,つまりalistやplistを作るとあまり使い勝手が良くないので避けたいと思うようになった. なぜなら標準的なリスト操作関数では比較をeqlで行うことが多い(要出展)ので,辞書構造を操作する際に文字列がキーだと支障をきたすことが多いからだ.
ちなみにJSONライブラリであるJSOWN
はキーが文字列となった状態でJSONオブジェクトを表現するので扱いにくい.これはまあJSONオブジェクトの特性上仕方がないことなのだろうが・・・
:test
を用いたナイーブな回避方法
このような場合に重宝するのは:test
キーワードを各種コレクション操作関数のオプションとして渡すことだ.:test #'string=
とすることで文字列のキーを正しく比較することができるようになる.
ただし,コレクション操作関数がライブラリなどに組込まれて使われていて:test
オプションを変更できない場合は対処不能だ.例えばパターンマッチライブラリtrivia
を使った以下のようなスクリプトについて考えてみよう.
(ql:quickload :trivia) (match '(("a" . 1) ("b" . 2)) ((alist ("a" . x) ("b" . y)) (cons x y)))
これはalist(("a" . 1) ("b" . 2))
の中の特定の箇所をパターンマッチによって取り出そうとする処理だが,このalistのパターンマッチは内部でassoc
による比較を利用しており,(相当面倒なことをしなければ)外から:test
を変更することができない.したがって,このパターンマッチは失敗する.
ちなみにassoc
は比較にeql
を使うので,以下のような場合はパターンマッチに成功する.
(ql:quickload :trivia) (match '((:a . 1) (:b . 2)) ((alist (:a . x) (:b . y)) (cons x y)))
自分がよくやる方法
ちなみに自分はmapcar
を使ってalistのキーを全てキーワードに変換してしまった.キーワード名前空間を汚してしまうが,手っ取り早い解決方法だ.
文字列からキーワードを生成するには,ALEXANDRIA
ライブラリのmake-keyword
が役に立つ.