よくやりがちな間違え1


※上記の広告は60日以上更新のないWIKIに表示されています。更新することで広告が下部へ移動します。

よくやりがちな間違え

ここではまだprologに慣れていない時に誤りがちな書き方と
修正方法について説明します・

以下のプログラムを見てみましょう。
test:-
 func(['A','A','A','A','A']).

func([]).
func(['A'|L]):-write('a'),func([L]).

述語funcの中に'A'が入っていれば小文字のaをコンソールに記述するプログラムです。
早速試してみましょう。

| ?-test.
ano

%traceしてみましょう
 Match   : test :-
               func([A,A,A,A,A]). %1回目
<< LAST CALL >>
[1] 0 Try   : func([A,A,A,A,A]) ?
 Match   : func([A,A,A,A,A]) :-
               write(a),
               func([[A,A,A,A]]).
[2] 1 Try   : write(a) ?
<< BUILTIN CALL >>
a [2] 1 Succ  : write(a)
<< LAST CALL >>
[1] 0 Try   : func([[A,A,A,A]]) ? %2回目
[1] 0 Fail  : func([[A,A,A,A]])

お気づきでしょうか?
変数Lはリストなので更にリストを付けて再帰しているため、
2回目のfuncのアリティが2重のリストになっています。
test:-
 func(['A','A','A','A','A']).

func([]).
func(['A'|L]):-write('a'),func(L).

||?-test.
aaaaa
yes
LOOP = 12
今度は上手くいきました。


次にA以外の文字が来たら何もしないといった処理を追加してみましょう。
何もしないから func([_|L]):-func(L). のような処理が必要です。
この時、追加する位置が異なると上手く動作しません。

test:-
 func(['A','B','A','A','A']).

func([]).                          %①
func([_|L]):-func(L).              %②
func(['A'|L]):-write('a'),func(L). %③

||?-test.
yes
LOOP = 7
prologは述語を上から順に探してユニファイしようと試みるので、
この場合先頭の一文字が何でもいいので無視する②で成功してしまうため、
③まで行かずに何もしないで成功して終了します。


test:-
 func(['A','B','A','A','A']).

func([]).                          %第1定義節
func(['A'|L]):-write('a'),func(L). %第2定義節
func([_|L]):-func(L).              %第3定義節

||?-test.
aaaa
yes
LOOP = 11
一部の例外や高速化したい時を除き、述語の位置は上から順に
第1定義節:停止条件
第2定義節:特定条件
第3定義節:無条件
と言った書き方をします。