Wählen Sie nun einen beliebigen Algorithmus mit 5 bis 30 Zeilen in einer Programmiersprache Ihrer Wahl aus.
Was beweist das Programm? Oder haben wir nicht auch "Programme als Beweise"?
Nehmen Sie den in Pseudocode geschriebenen GCD-Algorithmus:
function gcd(a, b)
while b ≠ 0
t := b
b := a mod b
a := t
return a
Was beweist es? Ich entschuldige mich für die Breite und Weichheit dieser Frage, aber ich wundere mich wirklich darüber.
Ja. Aber in der Regel sind die dazugehörigen Beweise uninteressant.
Denken Sie daran, dass wir unter der Korrespondenz haben
Schauen wir uns also Ihren Beispielcode an. Wir bekommen eine Funktion . Mit eben diesem Typ beweist sich das Programm
„Wenn es ein Element von gibt , dann gibt es ein Element von "
ein völlig uninteressantes Theorem, ich denke, Sie würden mir zustimmen. Vor allem die einfache Funktion , die auch einen Typ hat beweist denselben Satz. Warum? Weil es sich um zwei Funktionen des gleichen Typs handelt!
Nun, offensichtlich der Code für etwas Interessantes tut, also erweist es sich sicherlich als etwas Interessanteres als das Naive Funktion. Die Antwort auf diese Frage hängt davon ab, wie ausdrucksstark Ihr Typsystem ist. Wenn Sie nur Zugriff auf einen Typ haben , dann hast du leider Pech. Aber zum Glück können wir durch die Sprache der abhängigen Typen über interessantere Typen und damit interessantere Aussagen sprechen.
In der Welt der Softwareentwicklung verwenden wir Typen, um das gewünschte Verhalten eines Programms auszudrücken . Typen entsprechen Spezifikationen für Programme.
Auf der einfachsten Ebene sagen sie Ihnen, welche Eingaben und Ausgaben eine bestimmte Funktion erwartet, aber mit abhängigen Typen können wir das gewünschte Verhalten einer Funktion vollständig klassifizieren. Zum Beispiel könnte die naive Art von Mergesort sein
alles, was wir sehen, ist, dass es eine Liste von Dingen des Typs enthält und spuckt eine Liste von Dingen des Typs aus . Aber auch dies ist keine interessante Spezifikation. Die Identitätsfunktion oder sogar die Funktion, die ihre Eingabe ignoriert und die leere Liste zurückgibt, bewohnen ebenfalls diesen Typ. Und wieder, da Typen Sätze sind, sehen wir das beweist eine sehr uninteressante Aussage: "Wenn eine Liste von s existiert, dann eine Liste von s existiert .... wie .... ja, offensichtlich.
Also peppen wir unser Typensystem auf und sehen uns stattdessen so etwas an:
Ich verzichte auf einige Syntax und eine formale Definition von , aber hoffentlich ist klar, wie man eine solche Funktion schreibt.
Also jetzt muss eine strengere Spezifikation erfüllen. Es ist nicht erlaubt, eine Liste von zurückzugeben S. Es muss eine sortierte Liste von zurückgegeben werden S. Als Funktion dieses Typs beweist
„Wenn eine Liste von s existiert, dann eine sortierte Liste von s existiert"
Auch dies ist kein bahnbrechendes Theorem, aber es ist besser als das, was wir zuvor hatten.
Leider entspricht die konstante leere Listenfunktion immer noch dieser Spezifikation. Immerhin ist die leere Liste (leer) sortiert! Aber wir können wieder gehen. Vielleicht schreiben wir so einen Typ beweist
„Wenn eine Liste von s existiert, dann gibt es eine sortierte Liste von s mit genau den gleichen Elementen"
was als Vorschlag ein bisschen interessanter wird. Dies legt nun das gewünschte Verhalten von Mergesort fest. Überlegen Sie außerdem, wie Sie eine solche Behauptung beweisen würden. Wenn jemand sagte "beweise, dass eine sortierte Liste mit denselben Elementen existiert", würdest du sagen "sortiere sie einfach!" und das ist genau der Beweis dafür bietet.
Was dann, von Ihrem Beispiel? Nun, wie bei , funktioniert dasselbe Programm, um mehrere Dinge zu beweisen. Es ist wirklich der Typ , der zählt. Mit ein wenig Arbeit könnte Ihr Code ein Beweis dafür sein
„Wenn es zwei natürliche Zahlen gibt, dann gibt es eine natürliche Zahl, die beide teilt, die größer ist als jede andere natürliche Zahl, die beide teilt“
das beginnt, wie ein interessanter (wenn auch grundlegender) mathematischer Satz auszusehen!
Ich hoffe das hilft ^_^
gcd(a, b)
gleich ist while b ≠ 0; ...; return a
". (Vielleicht ist das aber nicht das, was Sie meinen, da dies keinen direkten Bezug zu den mathematischen Eigenschaften des ggT hat.)mergesort
richtig ist? Klingt nach einem Beweis, der einen Beweis seiner nichttrivialen Annahmen erfordert.Die Curry-Howard-Korrespondenz kann sowohl als „Beweise-als-Programme“ als auch als „Programme-als-Beweise“ angesehen werden, vorausgesetzt, wir spezifizieren, was die Logik für Beweise und die Sprache für Programme sind.
Die ursprüngliche Formulierung der Curry-Howard-Korrespondenz besteht zwischen Beweisen in einer bestimmten Logik (das implikationale Fragment der intuitionistischen Logik, auch bekannt als minimale Logik) und Programmen in einer bestimmten Sprache (einfach getippt -Rechnung ). Später wurde die Korrespondenz auf andere Logiken und Sprachen ausgedehnt (z. B. Minimallogik mit Implikation und Konjunktion und einfach getippt -Rechnen mit Paaren; Klassische Logik u -Rechnung ; usw.).
Ein entscheidender Punkt ist, dass die "Programmiersprache" in keiner Version der Curry-Howard-Korrespondenz Turing-vollständig sein kann . Tatsächlich ist die Logik, in der Beweise geschrieben werden, kohärent, und in der Beweistheorie bedeutet dies, dass ein Theorem namens Cut-Elimination oder Normalisierung gilt, das impliziert, dass jedes in der entsprechenden "Programmiersprache" geschriebene Programm seine Ausführung beenden muss. Nun ist bekannt, dass eine Sprache, die es uns nicht erlaubt, ein Programm zu schreiben, das sich endlos wiederholt, nicht Turing-vollständig ist.
Um Ihre spezielle Frage zu beantworten, das von Ihnen geschriebene Programm enthält das while
Konstrukt, das Endlosschleifen erzeugen kann, daher kann es keine logische Interpretation im Sinne von Curry-Howard haben, dh es entspricht keinem Beweis in irgendeiner Logik.
Es stimmt, dass es einige Problemumgehungen für diese Einschränkung gibt. Als Programmiersprache können wir zum Beispiel einfach typisiert betrachten
-Kalkül mit einem Fixpunkt-Kombinator, der Turing-vollständig ist (siehe auch eine Diskussion hier ). Bei dieser Variante wird der einfach getippt
-Kalkül while
kann das Konstrukt kodiert werden. Aber was ist der logische Inhalt einer solchen Programmiersprache aus der Curry-Howard-Perspektive? Nichts, denn der Fixpunkt-Kombinator würde einem Axiom in unserem logischen System entsprechen, das den Cut-Elimination-Theorem bricht.
Grob gesagt repräsentiert in der Beweistheorie ein Beweissystem ohne Schnitteliminationssatz eine inkohärente Logik, also eine "Nicht-Logik". Anders gesagt, Curry-Howard zeigt, dass es eine unüberbrückbare Spannung zwischen zwei wichtigen Aspekten gibt (siehe auch hier ): Kohärenz (in der Logik) und Turing-Vollständigkeit (in Programmiersprachen). Das eine schließt das andere aus, aber eine Logik ohne Kohärenz ist keine Logik, und eine Programmiersprache, die nicht Turing-vollständig ist, garantiert nicht, dass Sie das Programm schreiben können, das Sie schreiben möchten (aber es gibt „Programmiersprachen“ wie z System F , die auf Curry-Howard-Korrespondenz basieren und sehr ausdrucksstark sind, obwohl sie nicht Turing-vollständig sind).
Selbstverständlich sind in der Praxis verwendete Programmiersprachen wie C, Python, C++, Java, OCaml etc. Turing-vollständig und benutzerfreundlich konzipiert, also für beliebige Programmtypen
in einer dieser Sprachen geschrieben ist, ist es von Natur aus unmöglich, einen logischen Beweis dafür zu extrahieren
in jedem Beweissystem, es sei denn, das Programm verwendet sehr grundlegende Konstrukte, die in eine der "Programmiersprachen" übersetzt werden können, für die die Curry-Howard-Korrespondenz gilt (leider ist dies ziemlich selten, zum Beispiel ist es nicht der Fall, wenn das Programm enthält eine while
Schleife).
Lassen sei der gemessene Speicherplatz einer Maschine, auf der ein in Sprache geschriebenes Programm läuft , kann sein oder eine Norm Datentyp auf vielen Maschinen. Oder es könnte sein für einige .
Dies ist ein gutes Maß dafür, was das Programm tut: Das Programm wirkt auf die Register, den Cache, den Arbeitsspeicher und die Speicherung einer Maschine, und das deckt so ziemlich alles ab. Um an einen Port zu schreiben, würden Sie einen der oben genannten verwenden, z
Also dann ein Programm, das den Datentyp nimmt als Eingabe und Verdopplung (modulo ) sieht in Python so aus:
(Nehmen wir an, Python hat int32 und keine Ganzzahlen mit beliebiger Genauigkeit, was standardmäßig in der Standardversion von CPython der Fall ist.)
a = int(input("a="))
a = a << 1
Rufen Sie mit an python double_int.py 2
. Ich weiß, dass es keine Ausgabe an das Programm gibt, aber dies ist für ein theoretisches Argument. Also ein Programm
nimmt eine Maschine in gemessenen Zustand
und mutiert die Maschine so, dass sie sich im gemessenen Zustand befindet
.
Ich möchte sagen, dass ein Programm eine Implementierung eines Algorithmus darstellt so dass, wenn Sie das Programm ausführen auf seinem (notwendigerweise begrenzten, aber manchmal riesigen) Speicherplatz ), dh Sie rechnen für alle und das Ergebnis manuell überprüfen oder das Ergebnis mit dem Ergebnis eines vertrauenswürdigen anderen Programms vergleichen (Einheitentest) und das Ergebnis auscheckt, dann ist das Programm ein Beweis dafür ist in der Sprache realisierbar , und das ist in der Tat ein gültiger Algorithmus, der berechnet, was er sagt.
Also wann und es läuft ein Zeit oder weniger, kann man innerhalb weniger Sekunden bis zu einer Stunde einen "Proof of Algorithmus" überprüfen „Benutzung der Maschine , und das Programm .
Jan
D links neben U
D links neben U
Zhen Lin
D links neben U
Zhen Lin
D links neben U
Zhen Lin
D links neben U
Zhen Lin
Theodor Norvell