チューリング完全でない言語が世の中にあり、大学でComp Sciを勉強していなかったので、チューリング不完全言語( Coq など)ではできないことを誰かが説明できますか?
それとも、実際の実用的な関心がないことの完全性/不完全性(つまり、実際にはあまり違いはありません)ですか?
[〜#〜]編集[〜#〜]-の線に沿って答えを探していますXなどの理由で非チューリング完全言語でハッシュテーブルを作成してください!
まず、 チャーチチューリングテーゼ について聞いたことがあると思います。これは、「計算」と呼ばれるものはすべて、チューリングマシン(または他の多くの同等のもののいずれか)で実行できるものであると述べています。モデル)。したがって、チューリング完全言語は、任意の計算を表現できる言語です。逆に、チューリング不完全言語は、表現できない計算が存在する言語です。
わかりました、それはあまり有益ではありませんでした。例を挙げましょう。チューリングが不完全な言語ではできないことが1つあります。それは、チューリングマシンシミュレーターを作成できないことです(そうしないと、シミュレートされたチューリングマシンで計算をエンコードできます)。
わかりました、そのまだはあまり有益ではありませんでした。本当の問題は、チューリングの不完全な言語で書くことができない便利なプログラムは何ですか?まあ、誰かが有用な目的のために書いたすべてのプログラムを含み、すべてのチューリングマシンの計算を含まない「有用なプログラム」の定義を思いついた人は誰もいません。したがって、すべての有用なプログラムを記述できるチューリング不完全言語を設計することは、依然として非常に長期的な研究目標です。
現在、チューリングにはいくつかの非常に異なる種類があります-不完全な言語があり、それらはできないことで異なります。しかし、共通のテーマがあります。言語を設計している場合、その言語がチューリング完全であることを保証するための2つの主要な方法があります。
言語に任意のループ(while
)と動的メモリ割り当て(malloc
)があることを要求する
言語が任意の再帰関数をサポートすることを要求する
一部の人々がプログラミング言語と呼ぶかもしれない非チューリング完全言語のいくつかの例を見てみましょう。
FORTRANの初期のバージョンには、動的なメモリ割り当てがありませんでした。計算に必要なメモリ量を事前に把握し、それを割り当てる必要がありました。それにもかかわらず、FORTRANはかつて最も広く使用されていたプログラミング言語でした。
明らかな実際的な制限は、プログラムを実行する前に、プログラムのメモリ要件を予測する必要があることです。これは難しい場合があり、入力データのサイズが事前に制限されていない場合は不可能な場合があります。当時、入力データを提供するのはプログラムを書いた人であることが多かったので、それほど大したことではありませんでした。しかし、それは今日書かれたほとんどのプログラムには当てはまりません。
Coqは 定理を証明する のために設計された言語です。今 定理の証明とプログラムの実行は非常に密接に関連しています 、定理を証明するのと同じようにCoqでプログラムを書くことができます。直感的には、定理の証明「AはBを意味する」は、定理Aの証明を引数として取り、定理Bの証明を返す関数です。
システムの目的は定理を証明することなので、プログラマーに任意の関数を書かせることはできません。言語が、それ自体を呼び出したばかりのばかげた再帰関数を書くことを可能にしたと想像してください(あなたの好きな言語を使用する行を選んでください):
theorem_B boom (theorem_A a) { return boom(a); }
let rec boom (a : theorem_A) : theorem_B = boom (a)
def boom(a): boom(a)
(define (boom a) (boom a))
そのような関数の存在によって、AがBを意味することを納得させることはできません。そうしないと、真の定理だけでなく、何かを証明することができます。したがって、Coq(および同様の定理証明者)は任意の再帰を禁止します。再帰関数を作成するときは、常に終了することを証明する必要があります。これにより、定理Aの証明で実行するたびに、定理Bの証明が作成されることがわかります。 。
Coqの直接の実際的な制限は、任意の再帰関数を記述できないことです。システムはすべての非終了関数を拒否できる必要があるため、 停止問題 (またはより一般的には ライスの定理 )の決定不能性により、拒否される終了関数が確実に存在します。同様に。追加の実際的な難しさは、関数が終了することを証明するためにシステムを支援しなければならないことです。
AからBまでの関数がある場合、AがBを意味する数学的証明と同じくらい良いという保証を損なうことなく、証明システムをよりプログラミング言語のようにすることについて、多くの進行中の研究があります。より多くを受け入れるようにシステムを拡張する機能の終了は研究トピックの1つです。他の拡張の方向性には、入出力や並行性などの「現実の」懸念への対処が含まれます。もう1つの課題は、これらのシステムを単なる人間がアクセスできるようにすることです(または、実際にアクセスできることを単なる人間に納得させることもできます)。
同期プログラミング言語 は、リアルタイムシステム、つまり、プログラムがnクロックサイクル未満で応答する必要があるシステムをプログラミングするために設計された言語です。これらは主に、車両制御や信号などのミッションクリティカルなシステムに使用されます。これらの言語は、プログラムの実行にかかる時間と、プログラムが割り当てる可能性のあるメモリの量を強力に保証します。
もちろん、このような強力な保証に対応するのは、事前に予測できないメモリ消費量と実行時間のプログラムを作成できないことです。特に、メモリ消費量や実行時間が入力データに依存するプログラムを作成することはできません。
プログラミング言語になろうとさえしない特殊な言語がたくさんあるので、チューリング完全性からはほど遠いままです。正規表現、データ言語、ほとんどのマークアップ言語、...
ちなみに、 ダグラス・ホフスタッター は、計算に関する非常に興味深い人気の科学書をいくつか書いています。特に ゲーデル、エッシャー、バッハ:永遠の黄金の編組 。彼がチューリング完全性の限界について明確に論じているかどうかは覚えていませんが、彼の本を読むことは、より技術的な資料を理解するのに間違いなく役立ちます。
最も直接的な答えは、チューリング完全ではないマシン/言語を使用してチューリングマシンを実装/シミュレーションすることはできないということです。これは、チューリング完全性の基本的な定義に由来します。チューリングマシンを実装/シミュレートできる場合、マシン/言語はチューリング完全です。
それで、実際的な意味は何ですか?まあ、完全にチューリングしていることを示すことができるものはすべて、計算可能なすべての問題を解決できるという証拠があります。これは、定義上、完全にチューリングしていないものには、解決できない計算可能な問題があるというハンディキャップがあることを意味します。これらの問題が何であるかは、システムを非チューリング完全にするために欠落している機能によって異なります。
たとえば、言語がループや再帰をサポートしていない場合、または暗黙的にループをチューリング完全にできない場合、チューリングマシンは永久に実行されるようにプログラムできます。その結果、その言語はループを必要とする問題を解決できません。
別の例は、言語がリストまたは配列をサポートしていない場合(または、たとえばファイルシステムを使用してそれらをエミュレートできる場合)、チューリングマシンはメモリへの任意のランダムアクセスを必要とするため、チューリングマシンを実装できません。その結果、その言語は、メモリへの任意のランダムアクセスを必要とする問題を解決できません。
したがって、言語を非チューリング完全として分類する欠落している機能は、言語の有用性を実際に制限するものそのものです。つまり、答えは、それによって異なります。言語が非チューリング完全になる理由は何ですか。
Coqなどの言語に適さない重要なクラスの問題は、終了が推測されるか、証明するのが難しい問題です。数論にはたくさんの例がありますが、おそらく最も有名なのは コラッツの予想
function collatz(n)
while n > 1
if n is odd then
set n = 3n + 1
else
set n = n / 2
endif
endwhile
この制限により、Coqではそのような問題をあまり自然ではない方法で表現する必要があります。
チューリングマシンをシミュレートする関数を作成することはできません。 2^128
(または2^2^2^2^128
ステップ)のチューリングマシンをシミュレートし、チューリングマシンが受け入れられたか、拒否されたか、または許可されたステップ数より長く実行されたかを報告する関数を作成できます。
「実際には」、コンピュータが2^128
ステップでチューリングマシンをシミュレートできるようになるまでには長い時間がかかるため、チューリングの不完全性は「実際には」大きな違いをもたらさないと言っても過言ではありません。