Art of Prolog を読んでいて、Equation Solver(方程式ソルバー)を作るという記事があり、ふむふむと読んでいた。
その中で、Prologを勉強している人には常識かもしれないのですが、以下の様な記述があり「??」となった
方程式を解く際の移項を行う術語定義で
ikou(A+B=C,A=C-B).
などの記載や、
T=a*b^c
など。
例えば後者のTには一体何が入っているのか?
[a , * , b , ^ , c]
というリストなのか?
実際にSWI-PROLOGで問い合わせて調べてみた。
3 ?- T = a*b^c,atomic(T).
false.
atomicではない。
4 ?- T = a*b^c,atom(T).
false.
atomではない
5 ?- T = a*b^c,var(T).
false.
変数ではない。
8 ?- T = a*b^c,string(T).
false.
stringではない
10 ?- T = a*b^c,compound(T).
T = a*b^c.
というわけで、compound(複合項)らしい。
ちなみに
14 ?- T = a*b^c,T = [First|Rest].
false.
15 ?- T = a*b^c,T = [].
false.
リストへのマッチングが失敗するので、リストではない。
また、
16 ?- T = a*b^c,callable(T).
T = a*b^c.
callableが成功するので、実行可能な述語として認識されている。
それでは 複合項をリストに変換する =.. を使用して調べてみよう。
18 ?- T = a*b^c,T=..List.
T = a*b^c,
List = [*, a, b^c].
Listにした場合、 「*」 「a」 「b^c」 の3つの要素を持つリストとなる。
というわけで a*b^c という記述は 「*という演算子の引数として aとb^c を渡した*(a,b^c)みたいな複合項」 という
意味だということがわかった。
演算子の優先順位は
* 400
^ 200
で ^ のほうが高いため * のほうが外側の演算子ということで b^c はくっついているのであろう。
さらにb^cも枝の部分の複合項として認識されるので、
a*b^c = T という記述は、自動的に *(a, ^(b,c)) みたいな木構造の複合項として認識されているということがわかった。
どちらの演算子が親になるかはおそらく演算子の優先順位で決まるのであろう(実験およびマニュアル確認はしてません)
ちなみに、以下のようにした場合は
21 ?- T=a+b+c+d,T=..List.
T = a+b+c+d,
List = [+, a+b+c, d].
となるので、あくまで一番上位のレベルでは最後の演算子のみ認識され、それ以前の要素は枝として認識されている。
演算子の引数は2つのみということだろう。
これを利用して、以下のように 微分の導関数を求める述語も作れるようだ(実際はsin(x)の微分の定義など他のいろいろな述語定義が追加されます)
d( U^C, X, C*A*U^(C-1) ):-
atomic(C),
C\=X,
d( U, X, A ).
prolog derivative で検索するといくつかサンプルのソースがヒットするので興味のある人は探してみてください。
自分も興味を持ったので微分をする述語を作ってみようと思います。
完成したらこのブログに書きます(挫折するかも…)