Montag, 10. September 2012

Lispeln

In letzter Zeit interessiere ich mich immer mehr für die Programmiersprachen Scheme/Lisp, bzw. Allgemein für Programmiersprachen. Mein Ziel ist es, einen Schritt zurückzutreten, um mit etwas Abstand zu betrachten, was Programmieren überhaupt bedeutet. Was ist das eigentlich, Programmieren? Wie schreiben wir Programme? Was bestimmt beim Programmieren unser Denken?

Insbesondere will ich ein bisschen wegkommen, von den kleinlichkeiten, die einen so oft ereilen, wenn man über Programmiersprachen redet (Ich erinnere mich an endlose Diskussionen über geschweifte Klammern {} vs. begin end in Pascal, oder über für und wieder vom Array-Indizieren ab 1 oder 0... Diese Fragen haben mittlerweile für mich keine Relevanz mehr).

Der Punkt, der mich viel mehr interessiert ist, dass wir beim Programmieren einer Maschine mit begrenztem Verständnis aber starker Rechenpower beibringen, eine unserer Ideen zur Lösung eines Problems (Algorithmus) vermitteln, indem wir sie mittels einer Programmiersprache ausdrücken. Das hat viel mit "Abstraktion" zu tun, da wir für ein konkretes Problem (etwa beste Bahnverbindung zwischen zwei Städten) eine verallgemeinerte Lösung finden und dann die Lösung des Problems für einen Rechner, der in 0en und 1en denkt formulieren.

Schreibt man ein C Programm (oder Java, C++, Pascal, etc), so ist man nahe an der Rechnerarchitektur. Das wird gerne etwas verdrängt, etwa, wenn man sich zwischen Datentypen wie int und double entscheidet, so begründet man dies meist mit "ganze Zahlen" oder "reelle Zahlen". In Wahrheit jedoch, ist int nur ein kleiner Ausschnitt der ganzen Zahlen (2 hoch 32 Stück auf einem Pentium) und eine Variable vom Typ float kann nicht mehr oder weniger Zahlen beschreiben, welche jedoch über einen groesseren Bereich verteilt sind - viele Programmierer werden dennoch eine Variable vom Typ float für wesentlich genauer halten, als eine Variable vom Typ int.

Der Interessante Vorgang ist also folgender: Wir nehmen einen Abstrakten Lösungsansatz (Algorithmus) und formulieren ihn in einer Programmiersprache (Implementierung). Der Compiler übersetzt dies in Maschinencode und dieser wird vom Rechner ausgeführt.

Dies führt mich zum Knackpunkt der Geschichte:

Wodurch unterscheiden sich Implementierung und Kompilierung?

Man könnte sagen, der Mensch ist ebenso ein Compiler wie der Compiler auf dem PC. Kompilieren heißt ursprünglich soviel wie "Zusammenstellen", insofern liegt diese Sichtweise auch sprachlich durchaus nahe.

In dem wir die Welt in der Programmiersprache in Variablen, Typen, Funktionen einteilen und formulieren, leisten wir einen wesentlichen Teil der Übersetzungsarbeit um eine Idee auf einen Rechner zu bekommen.

Abstrakte Sprachen

Auslöser für diesen Blogpost ist meine Begegnung mit Lisp.
Lisp ist - abstrakt. Die Sprache berücksichtigt auf den ersten Blick kaum, wie der Rechner aufgebaut ist und ermutigt zu einer sehr mathematischen Sichtweise des Programmierens. Im Gegensatz zu den imperativen Programmiersprachen wie C/C++ haben Funktionen in Lisp eine viel größere Bedeutung, sie sind so flexibel einsetzbar wie Variablen. Daher auch der Vorwurf: zu komplex, zu mathematisch, zu unintuitiv.

Aber: Ist nicht das wichtigste an einem Programm seine Funktion?
Wer länger in Lisp programmiert, wird erleben, dass sich der Fokus vom "Wie stelle ich Daten am Computer dar" mehr auf das "Wie berechne ich etwas" verschiebt. Und dies ist ja die Frage, mit der  man sich ohnehin schon bei der Lösungsfindung auseinandersetzt.

Ich empfehle den Selbstversuch. Ein guter Ausgangspunkt ist ein Scheme interpreter wie Guile oder Racket und bestenfalls verschiedene Scheme Tutorials parallel anzuschauen (Structure and Interpretation of Computer Programs ist nur ein Beispiel).

Keine Kommentare:

Kommentar veröffentlichen