SSブログ

Prolog 手習い (2) [Prolog]

Prolog が少し分かってきたところで以前途中まで読んでいた The Reasoned Schemer を読み返したらだいぶ見通しがよくなっていた。理解を確かめるために The Reasoned Schemer (以下 TRS)の第1章のコードの一部を Prolog に置き換えてみた。

まず対話の10番。

run_10(Q) :- fail.

run_10 はフェイルしかしないので以下のように問うても解は無い。

?- run_10(Q).

No

11番。?- の Q と run_11 の中の Q は別物だけど共有されるので結果的に run_11 の中の Q の値である t が ?- の Q の値になる。

run_11(Q) :- t = Q.
?- run_11(Q).

Q = t ;

No

12番。conjunction の中にフェイルするものがあると全体がフェイルする。

run_12(Q) :- fail, t = Q.
?- run_12(Q).

No

23番。これは TRS でいうと (run* (q) (fresh (x) (== #t x) (== #t q))) という風に fresh というマクロを使って新しいローカルな変数を導入するところなんだけど Prolog では :- の右側に新たに出てくる変数は常にローカルである。これについては個人的には TRS みたいに明示的に導入するほうが Prolog 風よりも分かりやすいと思う。

run_23(Q) :- t = X, t = Q.
?- run_23(Q).

Q = t ;

No

26番と27番。= による単一化は左右入れ替えても同じ意味。

run_26(Q) :- X = t, t = Q.
run_27(Q) :- X = t, Q = t.
?- run_26(Q).

Q = t ;

No
?- run_27(Q).

Q = t ;

No

28番。instantiate されていない変数。SWI-Prolog では _Gnnn という形で表示される。

run_28(X).
?- run_28(X).

X = _G157 ;

No

30番。リスト構造。

run_30(R) :- [X, Y] = R.
?- run_30(R).

R = [_G205, _G208] ;

No

34番。単一化で矛盾が起こるとフェイルするので解が無い。

run_34(Q) :- f = Q, t = Q.
?- run_34(Q).

No

35番。矛盾しないなら何回でも = を使ってよい。

run_35(Q) :- f = Q, f = Q.
?- run_35(Q).

Q = f ;

No

37番。フレッシュな変数同士の単一化。次に見るように両者は共有される。

run_37(R) :- X = R.
?- run_37(R).

R = _G157 ;

No

38番と39番。X と Q を単一化するので X と単一化された値である t が Q の値にもなる。

run_38(Q) :- t = X, X = Q.
run_39(Q) :- X = Q, t = X.
?- run_38(Q).

Q = t ;

No
?- run_39(Q).

Q = t ;

No

47番。バックトラック。複数の解が見つかる。最後の fail の行は TRS にあわせたけど書かなくてもよい。これ以降は書かない。

run_47(X) :- olive = X.
run_47(X) :- oil = X.
run_47(X) :- fail.
?- run_47(X).

X = olive ;

X = oil ;

No

50番。フェイルするルールは飛ばされる。

run_50(X) :- virgin = X, fail.
run_50(X) :- olive = X.
run_50(X).
run_50(X) :- oil = X.
?- run_50(X).

X = olive ;

X = _G157 ;

X = oil ;

No

53番。再びリスト構造。

run_53(R) :- split = X, pea = Y, [X, Y] = R.
?- run_53(R).

R = [split, pea] ;

No

54番。さっきの X と Y の組み合わせに複数の解がある。

run_54(R) :- run_54_helper(X, Y), [X, Y] = R.
run_54_helper(X, Y) :- split = X, pea = Y.
run_54_helper(X, Y) :- navy = X, bean = Y.
?- run_54(R).

R = [split, pea] ;

R = [navy, bean] ;

No

そして54番の別解。一つの節の中に or があるのはあまり Prolog っぽくない?

run_54_2(R) :- (split = X, pea = Y; navy = X, bean = Y), [X, Y] = R.

58番。これはまず TRS の元のコードを先に挙げる。

(run* (r)
  (fresh (x y z)
    (cond-e
      ((== y x) (fresh (x) (== z x)))
      ((fresh (x) (== y x)) (== z x))
      (else fail))
    (== (cons y (cons z '())) r)))

TRS の fresh マクロはこういう風に任意の場所で新しくローカルな変数を導入できて、例えば4行目の fresh のなかの x は2行目で導入された x とは別であるということがポイント。これは Prolog にどう訳せばいいか?

こうやって新たな述語(run_58_helper_1 と run_58_helper_2)を導入するしかないか。まだ知らないだけで TRS の fresh 相当があったりいないかな。

run_58(R) :- run_58_helper(X, Y, Z), [Y, Z] = R.
run_58_helper(X, Y, Z) :- Y = X, run_58_helper_1(Z).
run_58_helper(X, Y, Z) :- run_58_helper_2(Y), Z = X.
run_58_helper_1(Z) :- Z = X.
run_58_helper_2(Z) :- Y = X.
?- run_58(R).

R = [_G205, _G208] ;

R = [_G205, _G208] ;

No

TRS 版だと内側の fresh のなかの z や y が自動的に外側の fresh で導入された z や y を指してくれるけど Prolog 版だとむしろそっちを渡して結び付けてやる必要がある。

上記のような例で外の X と中の X が別だというのは以下のようにするとはっきりする。59番。

run_59(R) :- run_59_helper(X, Y, Z), f = X, [Y, Z] = R.
run_59_helper(X, Y, Z) :- Y = X, run_59_helper_1(Z).
run_59_helper(X, Y, Z) :- run_59_helper_2(Y), Z = X.
run_59_helper_1(Z) :- Z = X.
run_59_helper_2(Y) :- Y = X.
?- run_59(R).

R = [f, _G208] ;

R = [_G205, f] ;

No

もし外と内の X が共有されていたら X=Y=Z でどちらも [f, f] になったところ。


nice!(0)  コメント(0)  トラックバック(0) 
共通テーマ:パソコン・インターネット

nice! 0

コメント 0

コメントを書く

お名前:
URL:
コメント:
画像認証:
下の画像に表示されている文字を入力してください。

トラックバック 0

Prolog 手習い (1)抽象化と見立て ブログトップ

この広告は前回の更新から一定期間経過したブログに表示されています。更新すると自動で解除されます。