いくつかの非常に良い答えがあります。私は議論に貢献しようとします。
Prologの宣言的論理プログラミングのトピックについては、Richard O'Keefeによる素晴らしい本「The Craft of Prolog」があります。非常に非効率的なプログラムを作成できるプログラミング言語を使用して、効率的なプログラムを作成することです。この本では、いくつかのアルゴリズムの効率的な実装について説明しながら(「プログラミングの方法」の章で)、著者は次のアプローチを取ります。
- 英語で問題を定義する
- 可能な限り宣言的な実用的なソリューションを作成します。通常、それはあなたがあなたの質問に持っているものをほとんど正確に意味し、ちょうど正しいProlog
- そこから、実装を改善してより高速にするための手順を実行します
これらの方法を進めながら、私にとって最も啓発的な(私にとって)観察ができました。
はい、実装の最終バージョンは、作成者が開始した「宣言」仕様よりもはるかに効率的です。まだ宣言的で簡潔で理解しやすいものです。その間に起こったのは、最終的な解決策が、初期の解決策が忘れていた問題の特性をキャプチャすることです。
言い換えれば、ソリューションを実装する際に、問題に関する知識をできるだけ多く使用しました。比較する:
すべての要素が昇順であるようなリストの順列を見つける
に:
2つのソート済みリストをマージすると、ソート済みリストが作成されます。すでにソートされているサブリストがある可能性があるため、長さ1のサブリストの代わりに、これらを開始点として使用します。
さておき、あなたが与えたような定義は非常に一般的であるため魅力的です。しかし、順列が組み合わせの問題であるという事実を意図的に無視しているという感覚から逃れることはできません。これはすでにわかっていることです!これは批判ではなく、単なる観察です。
本当の質問:前進する方法は?1つの方法は、コンピューターに宣言している問題に関する知識をできるだけ多く提供することです。
この問題を本当に解決するために私が知っている最善の試みは、アレクサンダーステパノフが共同執筆した書籍「プログラミングの要素」と「数学から汎用プログラミングへ」に示されています。悲しいことに、これらの本のすべてを要約する(または完全に理解する)ことはできません。ただし、入力の関連するすべてのプロパティが事前にわかっているという条件の下で、効率的な(または最適な)ライブラリアルゴリズムとデータ構造を定義するアプローチがあります。最終結果は次のとおりです。
- 明確に定義された各変換は、既に配置されている制約(既知のプロパティ)の改良です。
- 既存の制約に基づいて、コンピューターに最適な変換を決定させます。
なぜまだそうなっていないのかについては、コンピューターサイエンスは本当に若い分野であり、私たちは今でもそのほとんどの斬新さを真に評価することに取り組んでいます。
PS
「実装を洗練する」ということの意味を味わうために、たとえば、Prologでリストの最後の要素を取得するという簡単な問題を考えてみましょう。標準的な宣言的解決策は次のとおりです。
last(List, Last) :-
append(_, [Last], List).
ここで、の宣言的な意味append/3
は次のとおりです。
List1AndList2
連結であるList1
とは、List2
二番目の引数であるためappend/3
、私たち(アンダースコア)のみ一つの要素を持つリストを持っているし、最初の引数は無視され、我々は(リストの先頭を破棄し、元のリストの分割を取得するList1
のコンテキストでappend/3
)と需要こと戻る(List2
のコンテキストでappend/3
)は、実際には要素が1つだけのリストです。したがって、それは最後の要素です。
SWI-Prologのが提供する実際の実装は、しかし、こう述べています。
last([X|Xs], Last) :-
last_(Xs, X, Last).
last_([], Last, Last).
last_([X|Xs], _, Last) :-
last_(Xs, X, Last).
これはまだうまく宣言されています。最初から最後まで読んで、それは言います:
リストの最後の要素は、少なくとも1つの要素のリストに対してのみ意味があります。リストの末尾と先頭のペアの最後の要素は、先頭、末尾が空の場合、または空でない末尾の最後です。
この実装が提供される理由は、Prologの実行モデルを取り巻く実際的な問題を回避するためです。理想的には、どの実装が使用されるかに違いはないはずです。同様に、次のように言うこともできます。
last(List, Last) :-
reverse(List, [Last|_]).
リストの最後の要素は、反転リストの最初の要素です。
宣言型のPrologの良い点について決定的でない議論を行いたい場合は、Stack OverflowのPrologタグの質問と回答のいくつかをご覧ください。