飯高茂:Prolog で作る数学の世界

作成日 : 2008-03-16
最終更新日 :

概要

知る人ぞ知る Prolog と数学の本。

数学者が Prolog と出会った時の驚きと喜びを感じることができる。 レーザプリンタで出した原稿をそのまま版下としたところにも、その感情がわかる。 私は S-Prolog という、当時 (1990 年前後)利用できた処理系を使って少しずつ検証したのだけれど、 あるところまでいったら検証がうまくいかなくなって挫折した。 久しぶりにいじってみようかと思ったのだが、 今はどんな処理系があるのかわからない。

後記:今は GNU Prolog と SWI-Prolog を使ってみて、 SWI-Prolog のほうが良さそうなので、こちらでこの本の検証をしている (2008-04-08)。

後記:最近 RUN/PROLOG を懐かしんで作成された N-Prolog が利用できることがわかったので、こちらでもこの本を検証している(2022-12-24)。

検証

本書では、run/prolog というパソコンの処理系を使って検証している。 この処理系は、現在(2022年)は利用不可と思われる。 そこで本書の内容を、現在も利用可能な次の 3 種類の処理系で検証した。

結論を先に言えば、N-Prolog と swi-prolog ではほとんどが実行できたが、 gprolog では問題が多くあり、いくつか実行できなかった。


N-Prolog の場合

p.13 で説明されている、アリティを指定した述語を取り出すことが N-Prolog ではできない。

    ?- system(P/0).
    no

p.30 で本書では integer(123456) は no を返すが、N-Prolog では yes を返す。時代を感じる。

p.44 で、

?- edit(sum).
の入力で sum.ari という名前をもつファイルの編集に入るが、N-Prolog では拡張子はつかず、 sum という名前のファイルの編集となる。ファイルの拡張子をつけて編集するには、
?- edit('sum.pro').
のようにシングルクォーテーションが必要だ。

p.68 では一般互除法のアルゴリズムの説明がある。このアルゴリズムのプログラム

gcd(A=A*1+B*0).
gcd(D=A*X+B*Y):-
  res_q(A=B*Q+R),
  (A1,B1)=(B, R),
  gcd(D=A1*X1+B1*Y1),
  T is X1-Y1*Q, (X,Y) = (Y1,T).

を読み込ませると、N-Prolog では次のようにエラーが出る。line=11 は gcd(A=A*1+0*0). がある行だ。

?- consult('math-n.pro').
Syntax error assertz  gcd(A=A*1+B*0)
around here line=11 column=15

p.88 では append/1 を定義するプログラム 5.4 があるが、次のエラーが出る。

Permission error assertz  append(Z=[]+Z)
around here line=40 column=19

これは、すでに組み込み述語(拡張) append/3 があるためだ(system(P) で表示されるのは append/2 だがこれは誤り)。 アリティが違うが名前 append が衝突するためである。本書の append/1 を たとえば myappend/1 のように変更すれば問題ない。 なお、swi-prolog では append/1 のままの定義で正常に動作する。

swi-prolog の場合

13ページ、述語 system/1 は使えない。gprolog, swi-prolog ともに、current_predicate/1 である。

24-25ページ、前の式の修正方法は、 gprolog, swi-prolog とも、emacs 風キーバインドである。

29-30ページ、関数 integer/1 は四捨五入である。

§ 2.1 パターン・マッチ での

?- A*B=2+3.

で表示されるのは、no ではなく false である。

?- Z+Y=X+3.

で表示されるのは、
Z = X,
Y = 3

である。

gprolog の場合

4ページ、ベキ乗計算に ^ は使えない。** を使う。

7ページ、述語 concat は使えない。

13ページ、述語 system/1 は使えない。これは、swi-prolog でも同様に使えない。 gprolog, swi-prolog とも、current_predicate/1 である。

24-25ページ、前の式の修正方法は、 gprolog, swi-prolog とも、emacs 風キーバインドである。

29-30ページ、関数 integer は、切り捨て機能を持たない。 切り捨て機能をもつのは floor である。 これは、実数 r の整数部分の定義である。 r 以下の最大整数の意味に沿っている。 すなわち、floor(-5.6)は、正しく-6になる。

なお、integer は、引数が整数か否かを判定する述語としての機能はある。

31ページ、 pi/0 という定数関数はない。


p.50 の問題と私による解答例

/** 問1 0 から I までの 2 乗の和を求める述語 sqr_sum/2 **/
sqr_sum(0, 0).
sqr_sum(J, S1) :- I is J-1, sqr_sum(I, S), S1 is S + J * J.
/** 問2 0 から I までの N 乗の和を求める述語 power_sum/3 **/
power_sum(0, 0, N).
power_sum(J, S1, N) :- I is J-1, power_sum(I, S, N), S1 is S + J ^ N.

p.53 の問題と私による解答例

/** 問1 1 から N までの 逆数の和を求めるプログラム **/
inv_sum(1, 1.0).
inv_sum(J, S1) :- I is J-1, inv_sum(I, S), S1 is S + 1.0 / J.
/** 問2 省略 **/

問1 では、(S が4 を超えるのはNがいくつになればよいか. )という問もある。 これについては、次の結果から N が 31 になればいい」というのが答である。

?- inv_sum(30, S).
S = 3.994987130920391 .
yes
?- inv_sum(31, S).
S = 4.02724519543652

誤植

p.68 では一般互除法のアルゴリズムの説明がある。このアルゴリズムは、本書では次のプログラムで表される。

gcd(A=A*1+0*0).
gcd(D=A*X+B*Y):-
res_q(A=B*Q+R),
(A1,B1)=(B, R),
gcd(D=A1*X1+B1*Y1),
T is X1-Y1*Q, (X,Y) = (Y1,T).

最初の行は、正しくは次のとおりである。

gcd(A=A*1+B*0).

書誌情報

書名Prolog で作る数学の世界
著者飯高茂
発行日1990 年 6 月 20 日(初版第1刷)
発行元朝倉書店
定価2300 円(本体)
サイズA5 版
ISBN4-254-11054-5
備考現在手元にはない

まりんきょ学問所関数型言語Prolog > 飯高茂:Prolog で作る数学の世界


MARUYAMA Satosi