いつまでたってもPrologには慣れないなあ

単純なクエリなら理解できる。

father(ieyasu, hirotada).
father(hirotada, kiyoyasu).
granpa(D, A) <- father(D, M), father(M, A).

?- granpa(ieyasu, X).

とかすればX=kiyoyasuになることぐらいまでは。


たとえば、リスト二つをつなぎ合わせるappendをPrologでかくと以下

append([], R, R).
append([H | T], R, [H | A]) <- append(T, R, A).

これは直感的には考えてしまう。トレースをとれば理解はできるが。

?- append([1,2], [3,4,5], A0).

append([H=1 | T=[2]], R=[3,4,5], [H=1, | A1=?]) <- append(T=[2], R=[3,4,5], A1=?)
append([H=2 | T=[]], R=[3,4,5], [H=2, | A2=?]) <- append(T=[], R=[3,4,5], A2=?)
append([], R=[3,4,5], R=[3,4,5])
A2=[3,4,5]
A1=[2,3,4,5]
A0=[1,2,3,4,5]


Prologの強力なところは、どこに変数をおいてもいい。たとえば

?- append(T0, [3,4,5], [1,2,3,4,5]).

append([H=1 | T1=?], R=[3,4,5], [H=1, | A=[2,3,4,5]]) <- append(T1=?, R=[3,4,5], A=[2,3,4,5])
append([H=2 | T2=?], R=[3,4,5], [H=2, | A=[3,4,5]]) <- append(T2=?, R=[3,4,5], A=[3,4,5])
append([], R=[3,4,5], R=[3,4,5])
T2=[]
T1=[2]

T0=[1,2]

?- append([1,2], R0, [1,2,3,4,5]).

append([H=1 | T=[2]], R1=?, [H=1, | A=[2,3,4,5]]) <- append(T=[2], R1=?, A=[2,3,4,5])
append([H=2 | T=[]], R2=?, [H=2, | A=[3,4,5]]) <- append(T=[], R2=?, A=[3,4,5])
append([], R=[3,4,5], R=[3,4,5])
R2=[3,4,5]
R1=[3,4,5]

R0=[3,4,5]

もできる。

一つ一つをみれば単純なパターンマッチングだ。それが上→下はいいけど、下→上で行われると勘が働かなくなってしまう。あと、問い合わせのコードの上に結果が成り立っている想定がなされるんだが、直感的にわからなくなってるのはこの辺もある。ここは宣言的といってしまえばそれまでだが、一方向的に進む関数型言語でのそれとも違ってかんじる。

appendA acc [] l = acc ++ l
appendA acc [h|t] l = appendA (acc ++ [h]) t l
append l r = appendA [] l r

show $ append [1,2] [2,3,4]