Prolog 写経記 その 86 numbervars/3

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

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

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

今日は numbervars/3 を写経します.

解説

numbervars(Term, N1, N2)Term 中の変数を $var(N) の形式の項に具体化する.NN1 から N2 - 1 の間の整数である.

うーみゅ...
何を言ってるのかよく分からないのですが...
これも標準述語なの?
ごそごそ.
おぉ,SWI-Prolog にもありますね...
そのマニュアルの例.

?- numbervars(foo(A, B, A), 0, End).

A = '$VAR'(0)
B = '$VAR'(1)
End = 2

ふーん,解説とちょっと違って $var じゃなくて $'VAR' になってるけど,何をするのかは分かった.
でも,なんでこんなのが必要なのか分からない...

モード

numbervars(?, +, -)

ふむ.
第 3 引数を見れば変数がいくつあったか分かるわけね.

定義

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

numbervars2(Term, N1, N2) :-
	var(Term), !,
	Term = '$var'(N1),
	N2 is N1 + 1.
numbervars2(Term, N1, N2) :-
	Term =.. [_ | Args],
	numberargs(Args, N1, N2), !.

numberargs([], N, N).
numberargs([X | Rest], N, M) :-
	numbervars2(X, N, N1),
	numberargs(Rest, N1, M).

標準の述語とかぶるので,名前は numbervars にしちゃいました.


まずは本体の最初の節から.

numbervars2(Term, N1, N2) :-
	var(Term), !,
	Term = '$var'(N1),
	N2 is N1 + 1.

第 1 引数 Term が変数なら,それを具体化してます.
その記述なんですが...
うーみゅ,'$var'(N1) も一つの項なのか.ふーん.
そして第 3 引数を第 2 引数に 1 加えた値にしています.


次の節

numbervars2(Term, N1, N2) :-
	Term =.. [_ | Args],
	numberargs(Args, N1, N2), !.

これは第 1 引数 Term が変数じゃなかった場合.
その場合 Term は具体化された項なので,その引数のリストを Args に具体化し,それを下請けの述語で処理します.


その下請けの述語.

numberargs([], N, N).
numberargs([X | Rest], N, M) :-
	numbervars2(X, N, N1),
	numberargs(Rest, N1, M).

最初の節は停止条件
次の節では,引数リストの最初の要素を取り出して本体である numbervars/3 に渡しています.つまり再帰
そして残りのリストをこの述語自身の再帰呼び出しで処理します.


うーん,なんか分かったような分からないような.
一応,やってることは分かったからいいか.

注意

numbervars は具体化されていない変数を含む項を出力する際に役立つ.このような項を numberargs によってあらかじめ処理しておくと,変数の参照が $var(N) で書き換えられるため,見やすい出力となる.個々での定義は変数を例えば $var(N),$var(2),$var(3) などのかわりに 'A', 'B','C' などほかの項に具体化するよう変更できる.

見やすい?
デバッグ出力用ですか?
そうか,その程度のものか.ちょっと安心♪

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

6 ?- numbervars2(append(X, List, [X | List]), 1, _),
write(append(X, List, [X List])).
append($var(1), $var(2), [$var(1)|$var(2)]) X = '$var'(1) List = '$var'(2) Yes

ふむ.
それらしい出力になってますね.


では,X を具体化しておくと?

8 ?- X = ebiyuri,
numbervars2(append(X, List, [X List]), 1, _),
write(append(X, List, [X List])).
append(ebiyuri, $var(1), [ebiyuri|$var(1)]) X = ebiyuri List = '$var'(1) Yes

ふむ.


さらに List も具体化しておくと?

9 ?- X = ebiyuri,
List = [cancam],
numbervars2(append(X, List, [X List]), 1, _),
write(append(X, List, [X List])).
append(ebiyuri, [cancam], [ebiyuri, cancam]) X = ebiyuri List = [cancam] Yes

ふむ.