概要
SWI-Prologのマニュアルを漁っていたらThe recorded databaseなる項目があったので調べました。
Prologの基本的な使い方は、事実の定義 → 事実に対するクエリが基本ですが、この機能を利用すると構造化されたデータ(Term)をそのまま保存して取り出せるようになるようです。
Termについて
Termとは以下のような値のことを言う
- アトム
- name や 'Name' のようなアトム(文字列)
- 数値
- 整数や実数
- 変数
- 未バインドも可能
- 複合項
- person(1, 'name') のような複合項
Termの概要は以下の記事がわかりやすい
使い方
データの登録
データの登録は以下の述語で行う。
同一キーで登録した場合、上書きされるのではなく内部で保持しているTermのリストに追加される。
下記の述語はほとんど同じ動作であるが、Termリストへの追加の挙動がことなる。
-
recorda/2
,recorda/3
-
recordz/2
,recordz/3
recorda
は内部のTermのリストの先頭に積む
recorda(1, '1-before'),
recorda(1, '1-after'),
recorded(1, Value), % 先頭レコードの読み取り
writeln(Value) % 1-after
recordz
は内部のTermのリストの末尾に積む
recordz(1, '1-before'),
recordz(1, '1-after'),
recorded(1, Value), % 先頭レコードの読み取り
writeln(Value) % 1-before
データの読み取り
以下の述語でデータの読み取りを行う。
内部で保持しているTermリストの先頭から値を取ってくるようである。
サンプルコードは「データの登録」の項目を参照
-
recorded/2
,recorded/3
最新キーの取得
新規にTermを登録する際に、レコードのキーをどこまで利用したかわからなくなることがある。
その場合は、以下の述語で最大キーを取得して、+1 すればよい。
current_key/1
% 最大キーの値を取得する
recorda(1, 1),
current_key(Key), % レコード内
recorded(Key, Value),
writeln(Value) % 1
データの削除
登録したTermを削除したい場合は、以下の述語を呼ぶ
ただし、同一の述語の中では削除処理が完了せず、再度読み取りできてしまう点に注意
erase/1
以下のように記述すると削除したはずのデータが読み取れてしまう
recordz(1, '1-before'),
recordz(1, '1-after'),
recorded(1, Value1, Ref1),
writeln(Value1), % 1-before
erase(Ref1),
recorded(1, Value),
writeln(Value). % 1-before
これを解決するには transaction/1
を利用する
% databaseに追加
transaction((
recordz(2, '1-before'),
recordz(2, '1-after'),
recorded(2, Value1, Ref1),
writeln(Value1) % 1-before
)),
% databaseから削除
transaction((
recorded(2, _, Ref1),
erase(Ref1)
)),
recorded(2, Value),
writeln(Value). % 1-after
感想
SWI-Prologのマニュアルを漁っていたら面白い機能を見つけたのでまとめてみました。
Prologは基本的に静的な事実を定義して、それに対してクエリを発行して検索するというような感じで利用することが多いので、動的にデータを登録できる機能がデフォルトで備わっているのはいいですね。
利用するにあたって1つだけ注意しなければならないのは、「データの削除」の項目にもあるように、トランザクションを定義しておかないと、想定外の動作になることがあるという点です。
この点に注意さえすれば、簡単に構造を保存できるので、NoSQLライクに利用できるのではないかと思いました。