Prologを嗜む。

数学の真髄からPrologへ

おれは仕事で辛くなると、 辛さを和らげるためにソフトウェアを作り始めたりすることが多いのだが、 今回はPrologをやっている。

Prologというのは論理プログラミング言語の一つだ。 論理プログラミングというのは、pならqとか、そういった論理だけを並べることによって プログラムを書いてしまうという かなり数学寄りのプログラミングパラダイムのことだ。 関数型プログラミングよりもさらに抽象的に位置づけられる。 応用例としては以下のようなものがある。

  1. Prologを利用して日本憲法を厳密に定義したソフトウェア bitlow
  2. Jeopardyというクイズ番組でIBM Watsonという人工知能が優勝したことが 10年前くらいに少し話題になったが、 実はここでもPrologが使われている。 Natural Language Processing With Prolog in the IBM Watson System

なぜ、突然Prologなのかというと、 おれは最近数学の学び直しをしていて、 標準精講をトロトロとやっていたのだが、ちょっと寄り道したくなって 数学の真髄という本を読んでみた。

この本はとても面白かった。 おれは大学受験数学については比較的やった方だと思うが、 大学で数学を専攻したわけではない。 宅浪生は「学コン」をやれ

だからというと不適切かも知れないが、 こういった論理についてはぼんやりとは理解してるものの きちんと考えたことはなかった。 きっと多くの受験生がそうであろうと思う。

こうして、この数学の真髄という本を読んでいて、 論理の重要さを再確認したおれは論理プログラミング言語Prologに入門した。

Prologの入門方法

この記事を読んだ人の中にはPrologに興味を持つ人が現れるだろう。 だからまず、Prologの入門方法を教える。

まず、Prologにはいくつかの処理系がある。 その中でもメジャーなものはswiplという。

Macであればbrew install swi-prologでインストール出来る。 野心的なRust実装 scryer-prolog が進められているようだから、 Mの人はこっちを使うのもありかも知れない。

エディタはVSCodeのプラグインがあるのでそれを使ってもいいと思うが、 練習問題を解くくらいであればviでも苦労しない。

Prologに教材はない。 例えば、オライリーからPrologの本は出ていない。 以前には人工知能ブームがあったからか、Prologの参考書があったようだが、 最近では出ていない。

しかし、神戸大学の良いウェブサイトがあった。 おれが調査したところによるとこれが一番良かった。 どうやら神戸大はPEKというProlog専用の計算機を研究していたらしい。 このProlog入門ページもその開発に携わっていた田村直之さんのものである。 このことは読んだあとに知ったのであるが、どうりで良質なわけだ。

こういったものは、一旦読んでわかった気になったあと、演習を積む必要があるのだが、 その演習のためは P-99 という問題集がある。 おれは今、これを少しずつ解き進めているというわけだ。 とにかく難しくて、なかなか進まないが、つべこべ言わずに打つしかない。 Github

Prologは最難関の言語だ

難しい言語として最近良く話題になるのがRustだ。 その前はHaskellという言語が難しいと言われ、Haskellを書けるプログラマを採用して PHPを書かせるとかいうギャグも少しだけ流行った。 今だと、Rustを書けるプログラマを採用して、名前が似てるRubyを書かせるという罠もあるらしいから みなさんは気をつけてほしい。(参考: Rubyはゴミ言語。開発を中止すべき Rubyは環境に悪いゴミ言語。国策で禁止すべき

おれはこの両方とも多少は心得があるのだが、 Prologは遥かに難しい言語だ。 まさに最難関の言語だといえる。 これ以上難しい言語をおれは知らない。

論理だけでプログラミングをするというのがこんなに難しいとは思わなかった。 おれのような知的障害者はどうしてもデータを中心に考える。目に見えるからだ。 データや型をどうやって変形させるかをまず第一に考えてしまい、 それに囚われてしまう。

しかし、 論理プログラミングというものにはそもそもデータがない。 そこにあるのは論理だけである。 そこでは極めて数学的な思考が要求される。

P-99のP9は、リストの連続した要素をサブリスト化しようという問題だ。

?- pack([a,a,a,a,b,c,c,a,a,d,e,e,e,e],X).
X = [[a,a,a,a],[b],[c,c],[a,a],[d],[e,e,e,e]]

おれは結局この問題を自力では正確には解けなかったし(出力が逆順になってしまった)、 模範解法を理解するのにも1時間かかった。 その模範解法がこれだ。理解出来るだろうか?

pack([],[]).
pack([X|Xs],[Z|Zs]) :- transfer(X,Xs,Ys,Z), pack(Ys,Zs).

transfer(X,[],[],[X]).
transfer(X,[Y|Ys],[Y|Ys],[X]) :- X \= Y.
transfer(X,[X|Xs],Ys,[X|Zs]) :- transfer(X,Xs,Ys,Zs).

transfer(X,Xs,Ys,Zs)というのは [X|Xs]というリストから要素Xを連続してとった時に 残りがYsになり、連続要素はZsになるますという事実を語っている。

おれはこの最後の定義がなかなか理解出来なかったのだが、なぜかと考えると、 これは我々知的障害世界のプログラマとは発想が逆だからだ。 右の命題が真であれば左の命題が真であるということを言ってるのだが、 これはどうやって思いつけばよいのだろうか?

ちなみにおれが書いた誤解法が以下。 おそらくPrologに慣れていないプログラマは全員、こんな感じのコードを初手で 書いてしまうものと思われる。 発想がおかしいから、出力が逆順になってしまうのだ。 一言でいうと、左から右にデータを持っていってHeadにつけていくという思考ではなく、 上でいうところのZsのようにTailを右から左に持ってくるという発想が必要になる。 これが難しいのだ。

pack(L1, L2) :- pack(L1, [], [], L2).
pack([], [], L, L).
pack([], Ys, Acc, Zs) :- pack([], [], [Ys|Acc], Zs).
pack([X|Xs], [], Acc, Zs) :- pack(Xs, [X], Acc, Zs). 
pack([X|Xs], [Y|Ys], Acc, Zs) :- X \= Y, pack(Xs, [X], [[Y|Ys]|Acc], Zs).
pack([X|Xs], [Y|Ys], Acc, Zs) :- X == Y, pack(Xs, [X,Y|Ys], Acc, Zs).

Prologは頭の体操だ

よく、何かを勉強してると「それは何に役立つの?」という人がいる。 こういう薄っぺらいゴミ人間が最近は増えたように思う。

Prologが何の役に立つか? おそらく、Prologで仕事をすることはないだろうと思う。 自分でそれなりに大きなソフトウェアをPrologで書こうと思うこともないように思う。

では何のためにやってるのかというと、 単に頭の体操だ。

簡単なプログラムすらPrologで満足に書けないということに驚いてるとともに 感動している。 そんな経験は、今に至ってみるとなかなか出来ないものだ。 つまりこれは伸びしろであり、Prologの問題を解くことでプログラミングに対して 別の見方が出来るようになる可能性があるのだ。それはもしかしたらコードの質を 飛躍的に向上させるかも知れない。 Prologの思考が出来るようになればあるいは、世界の見方が変わる可能性すらある。 ワクワクする。

こういう可能性を、何の役に立つか界隈 (あるいはゴールから逆算しよう界隈) の人間は無視し続けるから、 結果として河野玄斗のような中学受験敗者の薄っぺらい人間が生産されてしまう。

人間の可能性を信じよう。

そもそもだがおれは生来、頭の体操を好む。 幼稚園や小学校低学年では多湖輝の頭の体操シリーズや ナンクロを解きまくった。 だから中学受験は簡単だった。猛烈に頭が良くなってしまったからだ。 パズル問題に強ければ、中学受験は秒殺出来る。

Prologも同じだ。 Prologもおれにとっては頭の体操であり、 実質的には何の意味もないかも知れないが、とにかく脳が汗をかくこと自体が快感というだけだろう。 スポーツをして汗をかくのが気持ちいいのと全く同じことだ。

ただし少しだけこじつけっぽくなるが、 Prologの考え方は、競技プログラミングにおけるDPと似ている。 したがって、Prologに慣れるとDP力は上がると思う。 しかし、ただDP力を上げるのであればDP問題を解きまくった方が早いだろうと思う。

というわけで、Prologが何の役に立つかはわかりませんが、 一緒にPrologを嗜みませんか。

関連記事


おすすめサプリです。おれも飲んでます。