M-Prolog SCBMの根本原理
M-Prolog ver1.0をリリースした後も、SCBMの設計についてどうしても納得できない部分がありました。そこでver1.01として、新しい方式を試みていました。
主な変更点は次の2点です。
- 失敗継続を、それを必要とする述語自身に生成させる方式
- 変数ポインタを成功継続に持たせず、独立した環境で保持する方式
しばらくこの2つの方式について追究していました。しかし結論として、どちらも採用しないことにしました。
失敗継続はどこで生成すべきか
1番目の方式については、単純なケースではうまく動作します。しかし、強制バックトラックがあり、さらに深い再帰とバックトラックを繰り返すような場合には、うまくいかないことが判明しました。
結局、もともとのver1.0の方式、つまり連言
P, Q
において、Pの実行後、Qへ進むところでPに戻るための失敗継続を生成する方式が、もっともKISSであることが分かりました。
重要なのは、Pだけを見て失敗継続を考えるのではなく、P全体の成功または失敗を、その次のQとの関係から考えることです。
Pの内部でどれほど複雑な再帰やバックトラックが行われようとも、それはPの内部で解決されるべき問題です。
Qから見れば、必要なのは「Pの別解を要求するにはどこへ戻ればよいか」ということだけです。
この境界を守ることで、制御構造は単純になります。
変数ポインタは成功継続に持たせてよい
2番目の方式も不採用にしました。
当初、成功継続に変数ポインタの情報を持たせた場合、複雑なバックトラックが発生すると、その一意性を保持できなくなるのではないかという懸念がありました。
そこで実際に、変数ポインタを独立した環境で管理する方式を実装してみました。
しかし、結果は同じでした。
当初の成功継続による方式でも問題がないことが分かりました。それならば、独立した環境を新たに導入するより、成功継続に必要な情報を持たせるほうがKISSです。
したがって、こちらについてもver1.0の考え方に戻ることにしました。
なぜver1.0を疑ったのか
そもそも、なぜここまで新方式にこだわったのか。
ver1.0では、本体部の先頭述語だけが特別な失敗継続を持つなど、一見すると非対称な部分があります。
私はこの点について、
「これは本当に正しい設計なのだろうか?」
という疑念を払拭できませんでした。
PrologやLispのような理論寄りの言語では、徹底的に考え抜かれた実装は最終的にきわめてシンプルなものになる、というのが私の経験則だからです。
そのため、コード上はよりシンプルに見える新方式のほうが、実は本来あるべき設計なのではないかと考え、かなりの試行錯誤をしました。
確かに新方式ではコードそのものはシンプルになります。
しかし、複雑なバックトラックには耐えられませんでした。
そこで分かったことがあります。
見た目の対称性やコード量の少なさと、制御構造としての単純さは同じではありません。
Prologの探索では、成功継続と失敗継続がそれぞれどの時点の状態を表しているのか、その境界が明確であることのほうが重要です。
その意味で、ver1.0の方式は単なる偶然ではなく、SCBMの根本原理に沿ったものだったのです。
SCBMはゴーカート
すでに実績のあるWAMが存在するのに、なぜSCBMという新しい方式にこだわるのか。
読者の中には疑問に思う方もいるでしょう。
WAMは、いってみれば高級スポーツカーです。
長年改良され続け、非常によくできています。しかし、それを分解してエンジン内部の構造まで理解することは容易ではありません。
一方、SCBMはゴーカートです。
F1レーサーが修業時代に乗る、あのゴーカートです。
こちらはメカがむき出しです。ステアリングを動かせば何が動くのか、アクセルを踏めば何が起きるのか、外からでも仕組みを見ることができます。
好きな人なら、その場でエンジンまで分解してしまうでしょう。
SCBMは、Prologの制御構造を可能な限りシンプルな形で、むき出しにして実装しようという試みです。
成功したらどこへ行くのか。
失敗したらどこへ戻るのか。
再帰したら何を保存するのか。
バックトラックしたら何を復元するのか。
それらがCのコードとして目の前に現れます。
コンパイラ好きには、たまらないものだと思います。
「車はつくるもんだぜ」
ちょうどギタリストのジェフ・ベックのようなものです。
彼は大の車好きで、自分でガレージカーを組み立てることでも知られていました。
同じギタリストのエリック・クラプトンに高級スポーツカーを自慢されたとき、ベックはこう言い返したそうです。
「車はつくるもんだぜ」
これがSCBMのココロです。
完成された高級スポーツカーに乗ることが目的ではありません。
自分でエンジンを組み、動かしてみる。
壊れたら分解する。
なぜ動くのかを考える。
そして、もっと単純な仕組みで同じことができないかを試してみる。
SCBMでやりたいのは、まさにそれです。
LLM時代のPrologへ
そして現在、私がSCBMの先に夢想しているのはLLMとの接続です。
Prologには、論理を手続きとして実行するための明確な仕組みがあります。
LLMには、自然言語や大量の曖昧な知識を扱う能力があります。
両者はかなり異なる世界から生まれました。
しかし、その違いこそが面白い。
LLMが生成した論理をPrologが厳密に実行し、その結果を再びLLMが解釈する。
あるいはLLMが必要とするとき、SCBMによってCコードとなった論理推論を直接呼び出す。
そんな形で、PrologのココロとLLMを接続できないか。
SCBMというゴーカートのむき出しのメカを眺めながら、私はそんなことを考えています。