- Prologは 節(clause) と term 中心のデータモデルひとつでプログラムを構成し、小さな文法だけで計算可能な関係を表現できる
- 宣言的な方式では実行手順よりも 何が成り立つか を記述するため、同じ関係を計算・生成・問い合わせのすべてに活用できる
- 純粋な Prolog は Horn clause と resolution に基づいており、制約の追加や節の追加が解集合に与える影響を論理的に予測できる
- プログラム自体が Prolog の term であるため、ほかのプログラムを読み、分析・変換しやすく、コンパイル時の書き換えによってドメイン特化言語も作れる
- ランタイムの動的性と、検索・単一化・制約伝播のような暗黙的メカニズムのおかげで、言語処理、データベース、検証、最適化まで幅広く活用されている
節と term でできた小さな言語
- Prolog のすべての データ は Prolog の term で表現される
- 中核となる言語要素は clause ひとつで、基本形は
Head :- Body. である
- 意味は Body が成り立てば Head が成り立つ ということ
- 中置演算子
(:-)/2 は右から左へ向かう矢印 ← を表す
- Head が常に成り立つなら
:- Body は省略できる
- 有用な最初の Prolog プログラムを書くには、この構造だけで十分である
- 既知のあらゆる計算はこのような節で記述できるため、Prolog は チューリング完全 な言語である
- チューリングマシンは、現在の状態やテープヘッド下の記号などから次の状態へ進む関係を節で記述する形で実装できる
- 実装例は turing.pl にある
宣言型プログラミングと関係中心の考え方
- Prolog は、解をどう見つけるかではなく、関心のある解について 何が成り立つか を表現する宣言型言語である
- この性質により、簡潔で明確かつ汎用的な仕様が可能になる
- リストと長さの関係は次のように記述できる
list_length([], 0).
list_length([_|Ls], N) :-
N #> 0,
N #= N0 + 1,
list_length(Ls, N0).
- 一部の Prolog システムでは、宣言的な整数算術を使うために別途ライブラリを読み込む必要がある
- この定義は宣言的には次のように読める
- 空リスト
[] の長さは 0 である
Ls の長さが N0 で、N が N0 + 1 なら、[_|Ls] の長さは N であり、この関係は N が 0 より大きいときにのみ成り立つ
- 同じ関係は複数の モード で利用できる
list_length("abc", L) は L = 3 を返す
list_length(Ls, 3) は長さ 3 のリスト形 Ls = [_A,_B,_C] を見つける
list_length(Ls, L) は空リストから長さが増えていくリストまで、一般的な答えを列挙する
- Prolog は通常 バックトラッキング によってすべての答えを報告する
length/2 は Prologue for Prolog の草案に含まれており、ほぼすべての Prolog 実装で同じ意味の組み込み述語として提供されている
論理プログラミングとしての Prolog
- 宣言型言語のカテゴリには、関数型プログラミング言語と 論理プログラミング 言語がある
- 関数は関係の特殊な場合であり、関数型プログラミングは論理プログラミングの制限された形と見なせる
- Prolog は logic に根ざしている
- 純粋な Prolog プログラムは Horn clause の集合で構成される
- 実行は resolution の特殊な場合と見なせる
- 形式論理とのつながりにより、プログラムの論理的性質に基づく 宣言的デバッグ を適用できる
- 制約を追加すると、解集合は最大でも縮小する
- 節を追加すると、解集合は最大でも拡張する
- 純粋な Prolog プログラムにおけるこの性質は 単調性 と呼ばれる
- Ulrich Neumerkel の GUPU system は、こうした考え方の応用例である
プログラムをデータのように扱うホモアイコニックな性質
- Prolog プログラムは有効な Prolog の term でもある
- この性質のおかげで、Prolog プログラムが別の Prolog プログラムを分析、変換、解釈しやすい
- 組み込み述語
read/1 で Prolog term を読めるため、Prolog clause も読める
- Prolog には、コンパイル時にプログラムを書き換える強力な マクロ機構 がある
- これにより、作業をより自然に解ける ドメイン特化言語 を実装できる
list_length(Ls,N) と N#>0 は表記上は異なって見えるが、Prolog の prefix、infix、postfix 演算子により、より読みやすい形で表現されているにすぎない
- たとえば Prolog term
+(a,b) は演算子記法で a+b と書ける
- 抽象構文は一様なので、書き方にかかわらずすべての Prolog term を読み取り処理できる
- 特定用途向けのユーザー定義演算子を動的に定義できる
ランタイムの動的性と拡張性
- Prolog プログラムはランタイムに容易に 生成、呼び出し、変更 できる
- この性質は表現力を高め、他の述語を引数に取る 高階述語 の実装を可能にする
- adaptive parsing のような非常に動的な手法も実装できる
- Prolog は、他のプログラマや一般ユーザーが提供するユーザー定義ルールで拡張されるプログラムを書くのに適している
- 純粋 Prolog 向けのインタプリタは Prolog コード 2 行で定義できる
- 関連内容は A Couple of Meta-interpreters in Prolog で扱われている
幅広い応用範囲と暗黙的メカニズム
- Prolog の関係的な性質は、プログラムを 柔軟で汎用的 にする
- この性質は 言語処理 や データベース における知識表現で重要な役割を果たす
- 現代の Prolog システムは、単純な logic puzzles から大規模アプリケーションまでに必要な機能を提供する
- Prolog の多才さと力は、検索、単一化、引数インデキシング、制約伝播 のような暗黙的メカニズムに根ざしている
- 開発者はこれらのメカニズムを活用し、多くの作業を Prolog エンジンに委ねられる
1件のコメント
Hacker News の意見
ここでの感情にはほぼ全面的に同意します。大学の AI の授業 3 科目で Prolog を使い、ほぼ『AI: A Modern Approach』全体と Prolog プログラミングを扱ったのですが、本当に思考様式がねじ曲げられる体験でした
Prolog 的に考え直すにはいつもウォームアップが必要で、その学期には他の言語でもひどく Prolog っぽいスパゲッティコードを書いてしまうことがありました。当時の最大の欠点は、他のものとの相互運用性が難しい点で、JVM の中に Prolog を入れるか、機能の少ない実装を使うか、C バインディングに頼る必要がありました。特定の作業、とくに制約充足問題には優れていますが、ユーザーインターフェースやファイルシステムアクセスのようなものが混ざると向いていないと思いました。当時は SWI も遅れていて、Sicstus のようなプロプライエタリなソリューションを使っていましたが、最近確認したところ SWI がプロプライエタリ実装に追いついており、今なら SWI を選ぶと思います。Prolog の試験は 60 分のライブコーディング 3 問に続いて口頭試問があり、大学で最も怖い試験でしたが、簡単な問題に 40 分使い、残り 2 問を数分で解いてうまく切り抜けました。後続科目ではゲームプレイエージェントを実装してトーナメントで競わせる課題が楽しく、『The Art of Prolog』と『The Craft of Prolog』は、今まで読んだプログラミング本の中でも指折りに良かったです
The Craft of Prolog も優れていますが、古い Prolog システムプログラミングに特化しすぎていて、今では古くなった章もあります。Prolog の多くのアイデアは解集合プログラミングと Datalog に生きており、Datalog は最新の静的解析器を作るのに優れています: https://arxiv.org/abs/2012.10086
ふと、チャットボットは Prolog をどう扱うのか気になります。十分に見たことがあるのでしょうか? そういうやり方で推論できるのでしょうか?
Prolog はクールで、馴染みのないプログラミングパラダイムを体験する楽しさだけでも学ぶ価値があります。多くの概念がまったく違う方法で表現され、パラダイムが腑に落ちると、むしろずっと単純になります
たとえば Prolog では通常、コレクションを直接操作せず、コレクションの項目が何であるかという情報を与えて、あとは実装に見つけさせます。依存関係ツリーを描くのも、エンティティとは何か、エンティティ X と Y の関係をどう判定するか、それをどう表現するかという 3 つの規則で可能です。ただし難しいので、学ばせたり使わせたりするよう説得するのは大変で、他のアプリにシームレスに統合する方法もまだ見つけられていません。FFI が選択肢なのは分かっていますが、プロダクション対応だとは納得できていません。ここ数か月、より「プロダクション」に近い Prolog の代替を探しましたが、LispWorks や Franz Allegro CL は高すぎるうえ、統合しやすいものではありませんでした。現代的なソフトウェアに Prolog をうまく統合した事例があるなら、本当に知りたいです。Mac で XPCE が動作しないので、GUI ソリューションも探しています。オンラインノートブックとして Swish も見る価値があります: https://swish.swi-prolog.org
今は削除されたと聞いているので「現代的」な事例ではありませんが、Prolog を適用した本当に美しい例です。https://news.ycombinator.com/item?id=36821871 から https://web.archive.org/web/20030218034509/http://www.resear... へとたどって読んでみる価値は大いにあります。関連リンク: https://news.ycombinator.com/item?id=14046420
どちらもかなりうまく動きましたが、ユースケースは限られていました。大学で Prolog を使った経験は楽しかったものの、本質的に Prolog 向きの形をした問題でないなら使いたくありません。少しでも複雑なものを実装し始めると抽象化が次々に漏れ出し、言語の利点を享受するというより、バックトラッキングアルゴリズムと格闘している感覚が強かったです
Racklog は Prolog 風の論理プログラミングを Racket に埋め込んだもので、「埋め込み」というのは Racket を失わないという意味です。Prolog 風のコード片と通常の Racket コードを並べて書けます。メタ論理や二階の「集合」述語を含め、Prolog の機能の大半を備え、Racket の部分式でより簡単かつ効率的にできる機能だけを除いています。https://docs.racket-lang.org/racklog/index.html Racket には GUI もあり、実際のところ必要なものはほぼ何でもあります
CUE は既存のワークフローにずっと入れやすいので、論理プログラミングの利点を実用的なものに変えやすいです。https://cuelang.org | https://cuetorials.com
数年間、C++でサプライチェーン最適化ソフトウェアを作りながら、ILOGの制約伝播ソフトウェア、現在はIBMが所有するSolverを使っていた。当時はBinPrologも検討した。範囲伝播が組み込まれていて、ネイティブx86にコンパイルされ、FFIの相互運用性も悪くなかった
それでも結局、SWI PrologとGNUツールチェーンの側に押されてしまったように思う。GUIはまったく別の専門領域として見るべきだと思うし、私たちは独自のC++キャンバスレンダリングエンジンと、「4D」または「Fourth Dimension」というひどい統合4GL開発ツールを使っていた。https://www.tomshw.it/data/images/2/0/4/3/infor-advanced-sch...
Mark TarverのShen言語には、Prologの完全な実装が入っている: https://shenlanguage.org/SD/Prolog.html
The Book of Shenの該当章もある: https://shenlanguage.org/TBoS/tbos_359.html Tarverは論理プログラミングについて、ソフトウェア付きの本も2冊書いている。Logic, Proof and Computation: https://shenlanguage.org/lpc.html Programming the Logic Lab: https://shenlanguage.org/logiclab.html
パターンマッチング、任意の型検査、内蔵Prologは驚きだった。創始者は外交的な態度のために、より広いコミュニティから排斥された面があるが、彼は優秀で、その導入はニッチかつ最先端にとどまっていた。Mozillaのような組織が背後にあれば、はるかに大衆的な魅力を持てたと思う。@deechの発表は今では古いが、それでもなお素晴らしく、有意義だ: https://www.youtube.com/watch?v=lMcRBdSdO_U, https://www.youtube.com/watch?v=BUJNyHAeAc8 ただし私はAPL/J/BQNの熱烈なファンなので、その点は割り引いて聞いてほしい
約25年前、AI+コンピュータサイエンスの学位課程でPrologを学んだ記憶がある。自然言語処理のモジュールでよく使った
最初はもどかしくて苛立ったが、慣れると意外に楽しく、反復をするには再帰しかなかったので、再帰の入門としても優れていた
大学では、主にそういう言語だけを使う数学者たちからPrologを学び、彼らにとってPrologは非常に自然な思考様式だった。逆に、手続き型言語ばかり主に使ってきた学生には混乱し、もどかしく、皆Prologを別の言語のように使おうとしてこじらせていた。Prologを使う3つ目か4つ目の科目で、その背後のアルゴリズムを学んでから、ようやくうまく使う方法が頭に入った。後にPrologで苦労していた学部生を手伝ったが、核心はPrologを既存の言語のように動かそうとするのではなく、問題解決の考え方をPrologの世界に合わせて変えることだった。かなり長く話した後、本当の腑に落ちる瞬間が訪れ、彼は課題を見事に終えた
だが新しいパラダイムが頭の中でぴたりとはまった後は、本当に好きになった。その気づきの瞬間だけでも、その授業を受ける価値は十分にあった
他のコメントはProlog全般について話しているが、The Power of Prologはかなり優れたチュートリアルシリーズだと言いたい
動画も見る価値があり、Markusは視聴者と読者の興味をうまくつかむ
この動画のおかげで、Prologをプログラミングにおける現在進行形で進歩的な動きとして受け止めるようになった
Prologは美しい言語だ。数学的推論、ルールベース推論などで数万行を書いたことがあり、そうした領域には完璧に合い、作業もとてつもなく楽しい
他の種類のアプリケーションには問題が2つある。第一に、パラダイムがあまりに違うため、ライブラリや他の言語とうまく合わない。第二に、まともなGUIを作るのがほぼ不可能で、これもやはりパラダイムと合わないためだ
通常、Prolog側では外部インターフェースがすべての引数が具体化された述語のように見え、外部側ではSQLデータベースを扱うようにPrologと相互作用する。クエリを送り、クエリを分解し、さらに多くの解を要求したり、バックトラッキングを駆動したりする、という具合だ。こうした相互作用が「面白くない」とは言えるかもしれないが、ライブラリがPrologの有用な機能を実際には活用していないため、そう動作するのだ。望むなら、より厚い相互運用レイヤーを作ることもできるし、複数のライブラリ関数をProlog側の単一の述語インターフェースにまとめたうえで、引数のインスタンス化モードに応じて特定のサブルーチンを呼ぶようにできる。しかしこれは、CライブラリをPythonのようなオブジェクト指向言語に公開するときに、複数のC関数を属性アクセサやデータ構造のメソッドのようにまとめることと大きくは変わらない
データ分析にPrologを積極的に使っている。最初は、問いを記号的な問題に変える方法を理解するため、できることは何でもPrologでやるよう自分を追い込む段階が必要だった
Prologは科学計算と文字列操作のサポートがひどいからだと思う。その段階を越えると、Prologによる解法は次善の選択肢よりもエレガントなことが多い。また論理パラダイムなので、否定による証明 + 単一化 = 論理プログラミング、という過程を理解するのに時間をかける価値がある。自分が学んだプログラミング言語の中で、間違いなく最も視野を広げてくれた言語だ
標準Prologには正規表現が標準搭載されていないが、人気のある実装はたいていそのためのライブラリを提供している。文字列処理をたくさんやる必要があり、CとPrologのどちらかを選ぶなら、間違いなくPrologを選ぶ。PythonとPrologなら、作業内容次第だ
いずれにせよ素晴らしいサイトだし、この話題がまた出てきてうれしい
以前Javaでソルバーを書いたことがあったので、そのコードをPrologに移植しようとしたが、まったく通用しなかった。結局最初からやり直して、Sudokuが妥当かどうかを検査する単純なPrologコードを書いたところ、その述語を実行すればSudokuを解くこともできると気づいた。そうして10行未満でソルバーを完成させた。本当にユーレカの瞬間だったし、Prologは非常に強力なのに、実務では不当に使われていない。幸い、DatalogとOWLに触れる機会はあった