世界を動かす技術を、日本語で。

論理プログラミングの実装

概要

  • 多くのプログラマーが 手続き型・OOP・FP には精通
  • 論理プログラミング は知名度が低く、実務利用も少ない
  • PrologやDatalogなど 関係性・述語 で問題を記述
  • データベース的な思考 や関係性のモデル化に強み
  • Pythonによる Datalogインタプリタ の基礎実装例を紹介

論理プログラミング入門と他パラダイムとの違い

  • 多くのプログラマーは 手続き型・OOP・FP (関数型)に慣れ親しみ
  • 主要なプログラミング言語は 三つのパラダイムすべて をある程度サポート
  • HaskellのIO/StateモナドやCの関数ポインタ構造体、Javaのストリーム利用など、パラダイム横断的な実装例
  • 論理プログラミング は知名度・普及度が低く、大学で触れる程度
  • 論理プログラミング は特定の問題に非常に有効

論理プログラミングの基本概念

  • OOPやFPは 手続き型 の延長として説明しやすい
  • 論理プログラミングは 関係(relation)や述語(predicate) で記述
  • 関数 は入力と出力が明確だが、 関係 は入力・出力の区別がない
  • Prologでの例
    • male(dicky). female(anne). のような 事実(fact) の宣言
    • parent(don, randy). のような 二項関係 の記述
    • father(X, Y) :- male(X), parent(X, Y). のような ルール(rule) の定義
  • クエリ例
    • ?- father(X, randy). → X=don
    • ?- father(don, X). → X=randy, X=mike, X=anne

述語・関係の拡張と再帰

  • 新たなルールの追加で 複雑な関係性 も簡潔に表現
    • son(X, Y) :- male(X), parent(Y, X).
    • sister(X, Y) :- daughter(X, P), parent(P, Y), X = Y.
    • ancestor(X,Y) :- parent(X,Y). ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).
  • 再帰的定義 で祖先関係なども自然に記述可能

Prologの課題とDatalogへの注目

  • Prologは 宣言的でない側面 があり、ルールの記述順が挙動に影響
  • SLD解決法 やバックトラッキングなど、実装依存の挙動
  • Turing完全であるがゆえの 無限ループや重複解答 のリスク
  • Datalog はPrologのサブセットでTuring完全でなく、 データベース的な利用 に最適
  • Datalogは SQLよりも関係性記述に長ける と評価

DatalogインタプリタのPython実装(概要)

  • 変数・値・述語使用(Atom) のデータ構造定義
    • class Variable, class Atom など
  • 述語(Predicate) は名前と引数数、事実集合、ルール集合を保持
  • ルール(Rule) はhead(結論)とbody(条件)から構成
  • Datalogクラス で全体の“データベース”を管理
  • Datalogでは
    • 否定や複雑な項の使用不可
    • すべての変数はbody内で登場必須
    • クエリ処理はナイーブなボトムアップ評価(fixpointアルゴリズム) で新事実を導出

Datalogの特徴と実用性

  • Turing完全でない ため、常に停止保証
  • データベース技術(B-tree, インデックス最適化等) の応用が可能
  • 部分評価や最適化 も容易
  • miniKanren のような関数型ロジック言語とは異なり、 状態管理型のデータベース的利用 が主眼

まとめ

  • 論理プログラミング は複雑な関係性のモデル化や推論に強み
  • Prologよりも Datalog の方が実用的なケースが多い
  • Python等の既存言語に組み込むことで、 既存のTuring完全な言語を補完
  • データベース・知識表現・推論エンジン の設計に有効

このように、論理プログラミングは「関係性のモデル化」や「推論処理」に特化したパラダイムとして、他のプログラミング手法とは一線を画す強みを持っています。特にDatalogは、既存のプログラミング言語やデータベース技術と組み合わせることで、実用性の高い知識処理基盤を構築可能です。

Hackerたちの意見

Sir Whinesalotの投稿のおすすめに賛成だよ(まだ全部読んでないけど)。miniKanrenとmicroKanrenを見てみるといいよ。数年前にmicroKanrenをOCamlに移植したとき、すごく勉強になったし、元のSchemeよりも少し理解しやすいと思う。ただ、理解するには論文を読む必要があるかもね。http://canonical.org/~kragen/sw/dev3/mukanren.ml miniKanrenの最も驚くべき成果は、前に進めたり後ろに進めたり、あるいは両方できるSchemeインタプリタだよ。http://webyrd.net/quines/quines.pdfでは、Schemeクワインを生成するのに使われているんだ。つまり、実行すると自分自身を出力するSchemeプログラムのことね(「miniKanren, Live and Untagged: Quine Generation via Relational Interpreters (Programming Pearl)」Byrd, Holk, Friedman)。SICPの§4.4にも、非常にアプローチしやすいSchemeでの論理プログラミングの実装があるよ。投稿とは違って、Datalogは論理プログラミングについて深い洞察を得る場所ではないと思う。むしろ、データベースについての深い洞察を得る場所だね。

SICP 4.4がとてもアプローチしやすいのに同意するよ。昔、簡単なPrologの課題があるクラスを受けたことがあって、建物の設計図をもらって、建物を通る道を解くプログラムを作ったんだ。ちょっと簡単すぎると思ったから、もっと深く掘り下げたくなった。単にタスクをこなすだけだと「これは魔法だ、これらの呪文を使えばいい」と感じるだけだったからね。Prologの実装方法を調べてみたけど、SICPのそのセクションを見つけるまで行き詰まってしまった。それで、JavaScriptに移植してProlog風の構文を与えて、課題を実行できるウェブページを作ったんだ。内部の仕組みも見せるようにして、それは今まで提出した中で一番面白いものだったよ。

インサイトなんてどうでもいい、データベース接続が肝だよ :P (記事を読んでくれてありがとう、前にmicroKanrenも実装したことがあるけど、完全な論理プログラミングエンジンを動かすのにこんなに少ないコードで済むなんて、すごいよね)

SICPの中にあるよ。https://t3x.org/amk/index.html 同じアプローチだね。古いバージョンの本が無料で手に入ると思うし、Scheme自体のものかもしれない。Schemeはホモアイコニックだから、クワインを作るのがかなり楽なんだよね。

最近、いろんなPrologの実装や制約処理ルールをいじってて、CLIPSにたどり着いたよ[0](パブリックドメインだけどNASAで開発されたんだ - かっこいいよね?)。ちょっと入りづらいけど、ルール解決がすごく速いし、純粋なCだから統合も簡単。論理言語を使ってスマートなコード解析を目指してるんだけど、これがなかなか期待できそう。Lispオタクだから、私には合ってるしね :)

https://ryjo.codes/ はこれに関してたくさんの作業をして、コースも作ったよ!

miniKanrenの実装について詳しく書いたのがここにあるよ: https://codeberg.org/ashton314/microKanren 最後には、小さな型チェッカーを実装して、逆に実行すると(型を与えることで)、その型に属するプログラムを列挙するんだ!

すごいね‽ LLMでその検索をガイドできるかな…

https://github.com/Seeker04/plwm 最近ここでPrologで実装されたウィンドウマネージャーが話題になってるよ。めっちゃクール!Prologを学ぶために新しい日常使いのツールとして使い始めたんだけど、実際に成功してる。開発者もすごくいい人で、基本的な質問や小さなPRに親切に答えてくれたよ。絶対おすすめ!興味がある人のためにGuixパッケージも持ってるよ。質の高い論理プログラミングのコードベースについてのおすすめの読み物ある?

Guixパッケージをどこかに公開した方がいいよ。

いいね!私は、構文や非線形変数の使用を妥協できるなら、結構好きな浅いバージョンのナイーブDatalogがあるよ。 edge = {(1,2), (2,3)} path = set() for i in range(10):

path(x,y) :- edge(x,y).

path |= edge

path(x,z) :- edge(x,y), path(y,z).

path |= {(x,z) for x,y in edge for (y1,z) in path if y == y1} 同じように、SQLを手書きで書くのも簡単で、見た目も似ていて、ストックデータベースエンジンから多くの機能とパフォーマンスを得られるよ。https://www.philipzucker.com/tiny-sqlite-datalog/ 最近、Z3 ASTからsqliteに小さなDatalogを書いたんだ。https://github.com/philzook58/knuckledragger/blob/main/kdrag...

わくわくするね!

Hacker Newsで議論の続きを見る