Prolog 写経記 その 61 counter_set/2

(ほぼ) 毎日淡々と Prolog を写経します.元ネタはこちら.

Prologユーティリティライブラリ

Prologユーティリティライブラリ

昨日で「4章 算術演算」は終了してました.
そんなわけで (どんなわけで?),今日からは「5章 カウンタ」へ進みます.
まずは counter_set/2 を写経します.


Prolog の変数は述語 (の節) に閉じたスコープを持つ,いわばローカル変数のみで,しかも一度値が具体化されると破壊的代入はできないわけですが,この章ではグローバル変数のようなスコープを持ち,値を増減することのできるカウンタを実装するようです.
なんかいやな感じ...
昨日の random/2 同様,えぐい方法を使う... んだろうなぁ.

解説

counter_set(Count, I) はカウンタ Count の値を望む数 I にセットする.

ふむ.

モード

counter_set(+, +).

ふむ.

定義

では,こいつの定義を写経しませう.

counter_set(Count, I) :-
	integer(I),
	counter_remove(Count),
	recorda(counter, counter(Count, I), _), !.

counter_remove(Count) :-
	recorded(counter, counter(Count, _), Ref), !,
	erase(Ref).
counter_remove(_).

下請けの述語 counter_remove/1 を使っています.
まずは本体から.
第 2 引数が整数かチェックした後,下請け述語 counter_remove/1 でカウンタをリセットして,recorda/3 でカウンタの値を設定しています.
この recorda/3,ISO 標準には含まれていないらしく,「Programming in Prolog (isbn:3540006788)」や「Prolog Programming for Artificial Intelligence (isbn:0201403757)」には解説されていません.
でもでも,SWI-Prolog はこれをサポートしていて,ドキュメントにも説明がありました.

recorda(+Key, +Term, -Reference)
Assert Term in the recorded database under key Key. Key is an integer, atom or term. Reference is unified with a unique reference to the record (see erase/1).

要するに第 1 引数をキーとして第 2 引数で指定された項を Prolog データベースに登録してくれるわけですね.


下請けの counter_remove/1 は二つの節を持ち,最初の節では recorded/3erase/1 を使っています.
recorded/3 は,第 1 引数で指定されたキーに対応する項 (recorda/3Prolog データベースに登録されたもの) とその「参照」を返します.
erase/1 は「参照」で示されたキーと項のマッピングProlog データベースから取り除いてくれます.
二つめの節はキーがまだ登録されていなかった場合でも述語が成功するようにするためのものですね.


counter_set/2 では,キーとして counter というアトムを使っています.
counter_set/2 の第 1 引数で指定されたカウンタの名前は Prolog データベースのキーそのものとしては使っておらず,登録される述語の引数として使われています.

注記

Prolog 定数ならどれでもカウンタの名前として用いることができる.カウンタの値としては整数がとられる.

ふむ.

では使用例を写経しませう.

counter_deccounter_inc 参照.

...
counter_deccounter_inc に続く...