これは宿題の質問ではなく、試験学習ガイドの質問です。 PrologとHaskellのパターンマッチングの違いは何ですか?
私はいくつかの調査を行いましたが、その背後にある理論を読んでも、2つの間の確固たる理解は得られません。私は、Prologでは、変数を統合する機能があり、したがって、解決を通じて推論し、可能な答えを吐き出すことができるため、パターンマッチングが異なることを読みました
eg ?- [a,b] = [a,X]
X = b
Haskellでパターンマッチングを表示する方法がわかりません。 HaskellはPrologのように統合できないため、Prologで示した同じクエリはHaskellでは機能しないことを私は知っています。 Haskellで同じ答えを得るには、警備員を通して明示的にそれを伝えなければならないことをどこかで覚えています。
私はそれをかなり理解していることを知っていますが、それを完全に理解して12歳に説明できるように、バーニースタイルを分解してくれる人が必要です。これはかなり長い間私を悩ませてきました、そして私は確かな説明を見つけることができないようです。
ちなみに、上記の例は、私がこれまでに学んだことと、実際に答えを見つけようとしていることを皆さんに表示するためのものです。私の主な質問は、上記の例ではなく、2つの違いについての完全な理解に関連しています。
プロローグパターンマッチングは、統一、具体的には Martelli-Montanari Algorithm (デフォルトでは発生チェックを除く)に基づいています。このアルゴリズムは、同じ位置の値を照合し、一方の変数をもう一方の対応する位置の値にバインドします。この種のパターンマッチングは両方の方法で機能する可能性があるため、Prologでは入力と出力の両方として引数を使用できます。簡単な例、_length/2
_述語。これを使用して(コメントでクエリを説明):
_?- length([],0). % is the length of empty list zero?
?- length([a,b,c],X). % what's the length of list consisting of a,b and c?
?- length(L,5). % give me all lists that have length of 5
_
Haskellパターンマッチング は、変数を指定された値のさまざまな部分にバインドする一方向のマッチングです。バインドされると、対応するアクション(右側)を実行します。たとえば、関数呼び出しでは、パターンマッチングによって、呼び出す関数が決定される場合があります。例えば。:
_sum [] = 0
sum (x:xs) = x + sum xs
_
最初の合計は空のリストをバインドし、2番目の合計は少なくとも1つの要素のリストをバインドします。これに基づいて、_sum <a list>
_が与えられると、結果は_0
_が_x + sum xs
_またはsum (x:xs)
と一致するかどうかに応じて、_sum <a list>
_または_sum []
_のいずれかになります。
HaskellとPrologの統合のようなパターンマッチングの違いは、両方の言語の変数の根本的に異なる役割に起因します。
Haskellでは、変数は値を保持します。具体的な価値観。そのような値は計算されていない可能性がありますまだ、そしてそれは⊥でさえあるかもしれませんが、そうでなければそれは1つの具体的な値です。 Haskellでは、変数を取ることはできず、その値のいくつかのプロパティを最初に述べるだけです。
したがって、パターンマッチングは常に、具体的な値がいくつかの変数を含むパターンと照合されることを意味します。このようなマッチングの結果は、失敗または変数の具体的な値へのバインドのいずれかです。 Haskellでは、これは一般的な比較の必要性を回避するためにさらに制限されています。これは、一致する用語に対してクラスEq
が定義されていることを意味します。
ただし、Prologでは、変数は可能な解決策のセットを参照する場合があります。変数はどこにでも発生する可能性があります。他の値の間のどこかに発生する可能性もあります。統合により、指定された等式が引き続き保持され、結果が最適に表現されるようになりました。つまり、最も一般的な統合子が計算されます。
| ?- length(L,5).
L = [_,_,_,_,_]
| ?- length(L,5), maplist(=(E),L).
L = [E,E,E,E,E]
したがって、PrologはここではL = [1,1,1,1,1]
やL = [[],[],[],[],[]]
のような具体的な値で答えませんが、それらすべての具体的な値を含む答えとして最も一般的な統合子を提供します。
次の非常に重要な違いについては誰も言及していません。 Prologでのパターンマッチングが試行されますすべての句に対して前の一致の1つが成功した場合でも(cutで短く停止されない限り)。しかし、Haskellでは、句のパターンマッチングは最初の成功までのみ試行されます。他の選択肢は試行されません(一致がguardによって拒否された場合を除く)。
Prologのパターンマッチングは、最も一般的な意味での等式制約を確立します(詳細については、@ falseによる回答を参照してください)。 共有は明示的です:A=B, A=5
セットB=5
同様に。これが可能なのは、Prologのlogvarがまだ設定されていない(つまり、uninstantiated)状態になっている可能性があるためです。これにより、結び目が簡単になります(実際には、基本的なプログラミング手法、つまり差分リスト)。
Haskellでは、変数は構文レベルで1回のみ定義できます。 Prologでは、logvarはset一度だけあまりにも(sansbacktracking)ですが、許可されています不完全な構造(データ)を指します。ここで、穴は、後の任意の時点で設定できる他のまだインスタンス化されていないlogvarによって表されます。
Haskellでは、保護された再帰で定義された特定の構造が、アクセスの要求に応じて徐々に具体化されます。 Prologでは、変数の最初のインスタンス化の後、その後の統合は用語の互換性と可能性の検証に変わりますさらに(おそらく再び部分的)インスタンス化( "いっぱいになります"穴明示的に)。
これは、昨日プロローグタグで遭遇したプロローグの統合がどのように用語を「構築」するかについての@chac(+1 btw)の言及をサポートするためにプロローグで興味深いと思う例です:
swapPairs([], []).
swapPairs([X], [X]).
swapPairs([X, Y|T], [Y, X|R]) :- swapPairs(T, R).
この述語には「本体」がほとんどありません。それは、その頭と再帰の中でその議論の統一を使用するだけです。
@chacと@LeleDumboの両方で指摘されているように、これはPrologの統合が「双方向」であるためです。
これがHaskellの穏やかな紹介がそれについて言っていることです:
Haskellのパターンマッチングは、Prologなどの論理プログラミング言語で見られるものとは異なります。特に、それは「一方向」マッチングと見なすことができますが、Prologは、評価メカニズムでの暗黙的なバックトラッキングとともに、(統合による)「双方向」マッチングを可能にします。
LeleDumboの答えに加えて、Prologの統合builds用語とdeconstructs用語がありますが、Haskellではビルドフェーズが戻り値に便利に要求されます。
もちろん、そのような機能は、純粋なPrologで、たとえばDCGで利用される、いわゆる「双方向」述語を可能にするものであり、いくつかの制限があり、解析と生成の両方に使用できます。