UP | HOME

Lisp-Besonderheiten

1 Arbeitsweise einer Blub-Umgebung

Um zu verstehen, warum Lisp anders ist als andere Programmiersprachen, schauen wir uns einfach an, welche Rolle der Compiler/Interpreter in einer Blub-Programmiersprache spielt: img/blub-compiler.jpg

Der Compiler liest einen ASCII-Text ein und gerneriert daraus den Objektcode. Dieser landet (eventuell auf Umwegen über das Dateisystem) im Hauptspeicher und wird dort zum Ablauf gebracht.

Während der Code abläuft, manipuliert er binäre Daten, die sich ebenfalls im Hauptspeicher befinden. Der Compiler selbst ist also ein Monolith, der nur ASCII versteht und nur Binärcode ausgibt.

Das Arbeitsprinzip hat den historischen Hintergrund, dass in der frühen Zeit der Computerei Computerspeicher viel zu knapp war, um den Compiler, den Objectcode und ebenfalls die durch diesen zu verarbeiteten Daten gleichzeitig darin unterzubringen. Diese Zeit ist nun längst vorbei. Trotzdem wurde das Prinzip auch für vergleichsweise junge Programmiersprachen wie Java ohne weiteres übernommen. Der Quelltext steht auf der Platte, der Compiler wird in den Hauptspeicher geladen, liest den Quelltext und schreibt den Objectcode auf die Platte. Von dort wird dieser wieder in den Hauptspeicher geladen und ausgeführt.

Dieses Arbeitsprinzip ist auch deswegen so fragwürdig, weil es die Möglichkeiten der genialen Von-Neumann-Architektur, die allen heutigen Computern zugrunde liegt, nicht wirklich ausschöpft. Diese sieht vor, dass die Computerprogramme sich im Hauptspeicher eines Computers befinden. Die Computerei hätte sich nie so rasant entwickeln können, wie sie es getan hat, wenn John von Neumann seine entscheidende Idee nicht gehabt hätte. Trotzdem ist es eigentlich unglaublich, dass die daraus erwachsende Möglichkeit eines Computers, an seiner eigenen Programmierung mitzuwirken, nur durch Lisp vernünfig umgesetzt wurde. Genau diese Fähigkeit, die das Wesen des Lisp-Makros ist, existiert in anderen Sprachen nicht.

Und das hat einen Grund, der in meinen Augen noch unglaublicher ist, als die halbherzige Nutzung der von-Neumann-Architektur durch die Blub-Sprachen: Es sind die Klammern bei Lisp, und die Art und Weise wie Sie von Programmieren anderer Sprachen beargwöhnt werden. Die Syntax von Lisp schreckt Programmierer ab, weil sie davon ausgehen, daß Syntax in dem Sinne vollkommen arbiträr ist, dass der Designer der Sprache sie gestalten kann, wie er möchte. Darum wird die Syntax von Lisp mit seinen vielen Klammern einfach als ein ästhetischer Fehlgriff gesehen1. Aber es gibt es einen sehr wichtigen Grund, warum Lisp-Programme so aussehen müssen, wie sie es tun.

2 Arbeitsweise einer Lisp-Umgebung

img/lisp-compiler.jpg

Die Klammern sind deswegen so entscheidend, weil sie eigentlich gar nicht da sind! Genauer: sie gehören nicht zum Lisp-Programm oder noch genauer: Der Compiler bekommt sie gar nicht zu sehen, da er mit Quelltexten nichts anfangen kann. Das liegt daran, dass das, was der Lisp-Programmierer schreibt, überhaupt kein Programmquelltext ist. Es ist die textuelle Darstellung einer Liste; daher die Klammern. Diese haben nur den Zweck, anzuzeigen, wo eine Liste beginnt und wo sie endet. Ihre Elemente sind entweder Symbole oder wiederum Listen. Das Lisp-Programm ist im Allgemeinen eine verschachtelte Liste. Da nun der Lisp-Compiler von den Klammern gar nichts wissen will, sondern nur Listen versteht, gibt es den Reader. Er setzt den Quelltext in einfach verkettete Listen 2 um. Damit er weiß, wie die Struktur beschaffen ist, benötigt er die Klammern. Erst "hinter" dem Reader befinden wir uns wirklich in der Lisp-Welt. Hier gibt es Listen, die Programme darstellen und solche, die Nutzdaten sind. Zwischen diesen gibt es keinen formalen Unterschied. Es darf ihn auch gar nicht geben, weil der Compiler die Listen, die Lisp-Programme darstellen als Daten ansehen können muss um sie zu übersetzen. Und genau dieses Szenario ist die korrekte Würdigung der Von-Neumann-Architektur!

Dadurch kann man in Common Lisp On-The-Fly die Definitionen von Funktionen und die Werte von Variablen verändern (Ja, sogar die Abänderung von CLOS3-Klassendefinitionen ist möglich und absolut gängige Praxis). Die neuen Definitionen werden vom Compiler sofort übersetzt und ersetzen dann ihre Vorgänger.

3 Zusammenfassung

  • Compiler für nicht-Lisp-Sprachen übersetzen ASCII-Texte in Maschinen- oder Bytecode. Weder ASCII-Texte noch Maschinencode lassen sich aber mit diesem Sprachen komfortabel verarbeiten.
  • Lisp-Compiler kennen keine ASCII-Texte. Sie übersetzen Lisp-Listen.
  • Dadurch können von Lisp-Programmen errechnete Listen wiederum dem Lisp-Compiler übergeben werden. Über diesen Weg kann der Programmierer das Front-End des Lisp-Compilers nach belieben erweitern und dadurch jede Spracheigenschaft hinzufügen, die er braucht.

Fußnoten:

1 "LISP = Lots of Superflous Irritating Parentheses" witzeln manche, und wissen dabei gar nicht, dass sie sich damit als Computer-Dilettanten geoutet haben.

2 Der deutsche Wikipedia-Artikel gehört zu den fehlerhaftesten im Bereich Informatik. Oben daher der Link nach en.wikipedia.org.

3 Das "Common Lisp Object System". Es arbeitet nach dem Metaobject Protocol und bietet Multimethoden

Author: Patrick Krusenotto (patrick.krusenotto@googlemail.com)

Date: 2014-10-08 22:56:52 CEST

Generated by Org version 7.8.11 with Emacs version 24

comments powered by Disqus