Kleiner Exkurs: utm-/smn-Theorem und Programmiersprachen...
... und unsere Nummerierungen von .
Da ich mittlerweile ein paar Mails zu diesem Thema bekommen habe, würde ich hier gerne noch etwas erläutern. Für viele ist das Theorem noch nicht greifbar. Ebensowenig die Nummerierung der einstelligen, berechenbaren Funktionen . Auch den Begriff Modellprogrammiersprache in Bezug auf haben ein paar gehört, können das aber noch nicht so ganz "anfassen". Ich versuche mal mal Glück, vielleicht wird es nach meinen Ausführungen für euch etwas deutlicher.
Achtung: während wir im Skript direkt nummerieren, gehe ich zunächst einen etwas anderen Weg. Also nicht erschrecken. Am Ende folgt die Auflösung.
Zunächst: Warum ist eine Programmiersprache?
Sicher habt Ihr schon einmal im Kurs imperative Programmierung (01613) oder Einführung in die objektorientierte Programmierung (01618) belegt. Dort programmieren wir in Java und Pascal. Was hat nun Java und Pascal mit uns und zu tun?!
Zäumen wir das Pferd mal von hinten auf.
Nehmen wir zunächst eine Funktion , d.h. unsere Identitätsfunktion aus . Im Endeffekt wollen wir diese Funktion auf unserem Computer, unserer Turingmaschine berechnen. Wir können, wie man sich leicht vorstellt, eine beliebige Funktion nehmen. Aber reicht für unsere Zwecke komplett aus.
So sieht unser Programm in PASCAL aus:
begin
writeln(ParamStr(1));
end.
Und so in Java
public static void main(String []args){
System.out.println(args[0]);
}
(Bitte nicht darauf festnageln, dass ich "public class" bei Java und "program" bei PASCAL vergessen habe, mir geht es nur um's Verständnis)
Wir sind uns einig, dass damit die Funktion berechnet wird? Gut. Und da wir eine Programmiersprache genannt und gesagt haben, dass es nur eine Programmiersprache zu geben braucht (Äquivalenz und so), nennen wir die Programmiersprache Java einfach (Kappa) und PASCAL (Omicron). Das sind also unsere Nummerierungen von , bzw. sollen es einmal werden.
Erinnert Ihr euch, wie definiert war? Das machen wir mit und genauso! Wir haben nur ein anderes Alphabet. Hatten wir bei das Alphabet , so sind wir bei und bei ein paar mehr Zeichen. Ich führe sie jetzt nicht alle auf, aber die paar sollten genügen. Wir müssen unsere Programme von oben mit Zeichen aus diesem Alphabet darstellen können:
Wie gesagt: nicht alle Zeichen drin. Hauptsache Ihr wisst, worauf ich hinaus will. Kommen wir nun zu unseren Nummerierungen und . Diese werden genauso definiert wie unser .
- Ordnungsfunktion und für die Alphabete und , so dass wir mit und die Nummerierung aller Worte aus und haben. Und wie bei nicht nur Programme, sondern auch Kauderwelsch wie z.B. .
- , z.B. als die Nummerierung des Bandprogramms . Es ist definiert durch:
Wir bekommen damit zur Nummer das zugehörige Bandprogramm wenn es tatsächlich ein Bandprogramm ist. Oder einfach nur eine Endlosschleife wenn die Nummer zu irgendwelchem Kauderwelsch gehört, denn mit haben wir (siehe oben) alle Worte über , d.h. auch Unsinn, nummeriert. - wird genauso definiert wie
- und . Damit bekommen wir zum den Worten und (Achtung: die Worte sind nach der Definition von und immer die Worte eines echten Bandprogramms aus der Sprache PASCAL () oder Java (). Auch wenn es Endlosschleifen sind, weil die Zahl nicht zu einem Bandprogramm, sondern zu Kauderwelsch gehört hat.
- Funktion mit . ist also die Funktion aus , welche die Funktion der Bandmaschine berechnet.
Warum haben wir kein und kein ? Sehen wir gleich!
Wir haben mit Java und Pascal also das gemacht, was wir mit getan haben. Nur nutzten wir nicht als "Programmieralphabet", sondern für unsere Zeichen der PASCAL-Programme und für Java.
Das führt uns zu ihren Kompositionen:
Die ebenfalls Nummerierungen von sind. Damit sie zu äquivalent sind, müssen sie das utm- und das smt-Theorem erfüllen. Kommen wir daher zum utm-Theorem.
utm-Theorem für und
Intuitiv wisst Ihr schon, dass beide Programmiersprachen das utm-Theorem erfüllen. Sie können interpretiert/compiliert werden und unsere Funktion berechnen. Das könnt Ihr im zugehörigen Compiler testen.
Und genau das ist unser aus der Definition des utm-Theorems:
Euch ist sicherlich auch klar, dass jeder Compiler/Interpreter für jede Programmiersprache unterschiedlich ist. Während ich für PASCAL Befehle wie "Writeln();" interpretieren und in Maschinencode für x86 (oder andere Prozessoren) übersetzen darf, muss ich für Java Zeug in Form von "System.out.println();" interpretieren. Während beide gänzlich unterschiedliche Worte über ihren Alphabeten und sind, so sind die daraus entstehenden Bandmaschinen jedoch gleich!
Und genau das ist der Grund, warum wir nur einmal definiert haben. Wir nutzten zwar unterschiedliche Programmiersprachen ( und ) und hatten natürlich auch unterschiedliche Programme , aber immer ein Berechnungsmodell, d.h. nur eine , z.B. die gleichen Assembler Befehle für einen x86 Prozessor (oder die gleichen Befehle für eine Turingmaschine).
Ich nehme also die Programmiersprachen-Kommandos "Writeln();" und "System.out.println();" und übersetze sie mit den zugehörigen Funktionen die gleiche Bandmaschine, die auf dem x86 Prozessor ausgeführt wird.
Nur haben wir oben nicht einen x86 Befehlssatz als Berechnungsmodell, sondern eine Turingmaschine gewählt. D.h. die Bandmaschine hat die Befehle in der Form, wie unsere Turingmaschine sie versteht. Denn die TM ist unser mathematisches, einfaches Modell für unsere Berechnungen. Und nach der Church/Turing-These ist sie genauso mächtig wie unser x86 Prozessor. Nur brauchen wir uns um die komplizierten Befehle des Prozessors nicht zu kümmern und verbleiben bei den überschaubaren Befehlen der TM 😉
Im Endeffekt hat also jede Nummerierung, d.h. jede Programmiersprache ihren eigenen Interpreter, die universelle Funktion , der die Befehle der Programmiersprache in die Befehle des Berechnungsmodells (sei es TM, x86, Registermaschine oder sonstwas äquivalentes) übersetzt.
Und da wir am Ende immer auf einem Berechnungsmodell landen (landen können, dazu gleich auch noch mehr), egal welche (äquivalente) Programmiersprache/Nummerierung wir verwenden, liegt ein Schluss sehr nahe: wir können zwei Äquivalente Sprachen auch ineinander übersetzen.
Und das ist dann auch der Bezug zum Übersetzungslemma, dem smn-Theorem. Nennen wir diese Funktion einfach mal , so können wir unsere Programmiersprachen Pascal und Java ineinander übersetzen, so dass mathematisch gilt:
Wie funktioniert, könnt Ihr euch sicher bereits im Kopf zurechtschustern. Z.B. würde uns die äquivalenten Befehle "Writeln();" und "System.out.println();" ineinander übersetzen: Tun wir mal so, als wären das Befehle funktionierender Programme, so haben sie durch die Nummerierungen und auch entsprechende Nummern. Seien die willkürlichen Nummer der beiden Befehle:
und
,
so übersetzen wir mit letztendlich:
Wie geht dazu vor? nutzt einfach die universellen Funktionen von und . Da beide Interpreter am Ende die gleiche Bandmaschine für "Writeln();" und "System.out.println();" ausspucken, können wir das problemlos tun.
Und hier kommt das "Mehr" und die Auflösung
Wir sind sogar nicht einmal auf das gleiche Berechnungsmodell, bzw. die gleiche Bandmaschine angewiesen. Auch wenn unsere Programmiersprachen gänzlich andere Berechnungsmodelle füttern (z.B. wir interpretieren PASCAL für x86 und Java für ARM), so haben wir dennoch eine gemeinsame Basis! Die Nummern beider Programme werden zwar auch auf anderen Berechnungsmodellen (x86 und ARM) ausgeführt, haben alle eigene Bandmaschinen , berechnen aber die gleiche Funktion aus !
Denn hier führt am Ende alles hin: egal welche Programmiersprache und welches Berechnungsmodell. Haben wir eine Programmiersprache/Nummerierung, die eine berechenbare universelle Funktion (utm-Theorem) besitzt und das smn-Theorem erfüllt, so sind diese äquivalent und berechnen alle das Gleiche: die Funktionen aus .
Und da das so ist, kann ich PERL weiterhin Java und PASCAL guten Gewissens vorziehen 😉
Sie können zum Ende springen und ein Kommentar hinterlassen. Pingen ist im Augenblick nicht erlaubt.