Prologとは何者か

Prologは1970年代初頭にフランスで生まれた論理プログラミング言語で、名前は「Programmation en logique(論理によるプログラミング)」の略です。主な設計者はAlain Colmerauerで、AIや自然言語処理、定理証明などを想定した言語として作られました。

大雑把に言うと、Prologは「どう計算するか」ではなく「何が真か(どんな関係が成り立つか)」を書く言語です。

  • 事実 (fact): 「太郎は花子の親だ」といった関係
  • ルール (rule): 「XがYの親で、YがZの親なら、XはZの祖先だ」のような推論ルール
  • クエリ (query): 「花子の祖先は誰?」といった質問

典型的な例はこんな感じです:

parent(taro, hanako).
parent(hanako, jiro).

ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).

?- ancestor(X, jiro). と問い合わせると、X = hanako ; X = taro のように、条件を満たす解をバックトラッキングで順に返してくれます。

アルゴリズムを手続き的に書くというより、「関係」と「そこから導けること」を書いていくイメージです。


制約問題とProlog

Prologは元々「Horn節による論理プログラミング言語」ですが、そこから派生した**制約論理プログラミング(Constraint Logic Programming, CLP)**の世界では、Prolog風の書き方で数理最適化やスケジューリングに近いことができます。

代表的なのが整数に対する制約を扱う CLP(FD)(Finite Domains)で、多くのProlog処理系(SWI-Prologなど)には clpfd ライブラリとして組み込まれています。

特徴はだいたいこんな感じです。

  • 変数にとりうる値の範囲(ドメイン)を指定する
  • 「全て違う」「合計が何になる」「この順序関係を満たす」などの制約を書く
  • ソルバが整合する組み合わせを探し、解を返す

「探索+制約伝播」をエンジンがやってくれるので、素朴なバックトラッキングよりもずっと効率良く解を見つけてくれます。


実際にPrologで書いた制約問題の例

具体的なコードを1つだけ書いてみます。「3つの会議A, B, Cを、1〜3コマ目の時間枠に割り当てたい」という小さなスケジューリング問題です。

条件:

  • 各会議は別々の時間枠(同じ時間には被らない)
  • 会議Aは1コマ目ではない
  • 会議BはAより後ろの時間にしたい
  • 会議Cは3コマ目ではない

SWI-Prolog+clpfd を想定したコードはこんな感じになります。

:- use_module(library(clpfd)).

schedule([A, B, C]) :-
    Vars = [A, B, C],
    Vars ins 1..3,          % 各会議は1〜3コマ目のどこか
    all_different(Vars),    % 同じ時間には入れない

    A #\= 1,                % Aは1コマ目以外
    B #> A,                 % BはAより後ろ
    C #\= 3,                % Cは3コマ目以外

    labeling([], Vars).     % 解を具体的な数値に落とす

これをロードして ?- schedule(S). と聞くと、例えば

S = [2, 3, 1] ;
false.

のような解が返ってきます(A=2コマ目、B=3コマ目、C=1コマ目)。

ポイントは、制約そのものがコードになっていることです。

  • Vars ins 1..3 で値の範囲
  • all_different(Vars) で「被らない」条件
  • A #\= 1, B #> A, C #\= 3 がビジネスルール相当

制約を足したり緩めたりするだけで問題設定をいじれるので、試行錯誤しながらモデル化するのに向いています。


LLM+Prologでのハイブリッド構成

最近よく話題になるのが、LLM(大規模言語モデル)とProlog/CLPを組み合わせる構成です。それぞれ得意分野がかなり違うので、上手く役割分担させると相性が良いです。

ざっくりした分担はこんなイメージです。

  • LLMの担当
    • 自然言語の入出力
    • あいまいな要求の整理(例:「会議が被らないように調整して」)
    • Prolog用の事実・ルール・制約のテンプレート生成
  • Prolog/CLPの担当
    • しっかり定義された制約に基づく探索・推論
    • 解の完全性(「他に解はあるか」など)をきちんと扱う
    • 失敗の理由を構造的に説明する(どの制約が矛盾したか)

典型的なフロー例

  1. ユーザが自然言語で指示
    • 例:「AさんとBさんは同じ時間に会議を入れたくない。9〜12時の枠で会議を組んで」
  2. LLMがテキストを解析し、内部的な制約表現を組み立てる
    • 「参加者」「時間枠」「禁止条件」などのスロットに落とし込む
    • それをProlog/CLPに渡しやすい形(JSONやPrologコード)に変換
  3. アプリケーション層がPrologエンジンを呼び出す
    • 例:HTTP経由でPrologサーバに schedule(A, B, ...) のようなクエリを投げる
  4. Prologが制約を解き、解や「解なし」を返す
  5. LLMが結果を自然言語で説明
    • 「Aさんは9時、Bさんは10時に入れると全員の条件を満たせます」といった要約
    • 解がない場合は、「この条件だと会議が組めない理由」を補足する

ハイブリッドにする利点

  • LLMだけに任せると、論理的整合性が崩れた“それっぽい回答”が紛れがち
  • Prologだけだと、自然言語での指示や非構造データの取り回しが面倒

両者を組み合わせると、

  • LLMで柔らかく要件を取り込んで、
  • Prologでカチッと制約を満たす解を出す

という構図が作れます。


さいごに

Prologは「昔のAI言語」というイメージを持たれがちですが、制約プログラミングや知識表現の文脈では今でも十分現役です。

  • 論理・関係をそのままコードにしたいとき
  • スケジューリングやパズルのような制約問題をモデル化したいとき
  • LLMの“言語能力”と組み合わせて、より堅牢なシステムを作りたいとき

こういった場面では、一度Prolog/CLPを候補に入れてみる価値があります。

実験するなら、まずはSWI-Prolog+clpfdで簡単な制約パズルを書いてみるところから始めるのがおすすめです。