Homoikonische Python-Sprache
(aljamal.substack.com)McCarthys „Lisp in Lisp“ in Python implementieren
-
Lisp, das John McCarthy Anfang der 1960er-Jahre entwickelte, besitzt die Eigenschaft der Homoikonizität, sodass Code und Daten gegeneinander austauschbar sind
- In Lisp wird die Grenze zwischen Code und Daten unscharf
- Dadurch kann Lisp sich selbst auf natürliche Weise ausdrücken
-
Der halbe Seitenabschnitt Code unten auf Seite 13 des Lisp-1.5-Handbuchs war Lisp selbst
- Alan Kay nannte das die „Maxwell-Gleichungen der Software“
- Die gesamte Welt der Programmierung ist in nur wenigen Zeilen Code komprimiert
-
Um das zu verstehen, ist es eine gute Methode, den Code „Lisp in Lisp“ mit Python nachzubauen
- Die meisten Programmierer sind mit der Lisp-Syntax nicht vertraut, aber mit Python-Syntax schon
- Ziel ist es, den Geist des Lisp-Codes so weit wie möglich zu bewahren und ihn in Python neu zu schreiben
M-Expression und S-Expression in Lisp
-
Lisp hatte ursprünglich zwei Syntax-Varianten
- M-Expression (Meta-Ausdruck): die Code-Variante
- S-Expression (symbolischer Ausdruck): die Daten-Variante
- Beide sind semantisch gleichwertig
-
Der Code „Lisp in Lisp“ wurde in M-Expression geschrieben und implementiert S-Expression-Lisp
-
Eine Möglichkeit besteht darin, Lisp-M-Expressionen in Python-Code-Strukturen zu übertragen und S-Expressionen als Python-Listen darzustellen
- Lisp steht für List Processing und verwendet nur die einzelne Datenstruktur Liste
Erste Implementierung
-
Mit den grundlegenden Python-Listenfunktionen werden die Basisoperationen von Lisp implementiert
- atom(x): prüft, ob x eine Liste ist
- eq(x,y): prüft, ob x und y gleich sind
- car(x): gibt das erste Element der Liste zurück
- cdr(x): gibt den Rest der Liste zurück
- cons(x,y): fügt ein Atom zu einer Liste hinzu
- append(x,y): fügt zwei Listen zusammen
-
Einige rekursive Grundbausteine werden ausgelassen, und mit Hilfe von Llama3-70b lässt sich schnell ein Interpreter für eine Teilmenge des Codes „Lisp in Lisp“ implementieren
Zweite Implementierung
-
In der ersten Implementierung fehlt die Lambda-Funktionalität
- Lambda ist in Lisp die zentrale Methode, um Funktionen zu definieren und aufzurufen
- Ohne Lambda lässt sich keine Rekursion implementieren, und ohne Rekursion ist es nicht Turing-vollständig
-
Um Lambda zu implementieren, werden die Grundbausteine assoc(x,y) und pairlis(x,y) benötigt
- assoc(x,y) ist ein key/value-Dictionary-Lookup mit einer Assoziationsliste
- pairlis(x,y) entspricht dem Python-
zip(x,y)
-
Lisp hat keine loop-Konstrukte, daher musste selbst für eine einfache lineare Suche Rekursion verwendet werden
- In Python lässt sich das jedoch elegant mit Listenkomprehensionen umsetzen
- Das gilt ebenso für evcon und evlis
-
Die Funktion eval nimmt im ursprünglichen Lisp zwei Argumente an
- Das erste ist ein Ausdruck (s-exp), das zweite die Umgebung (environment) als key/value-Liste
- Die Umgebung hält die Variablenbindungen von LAMBDA fest
- Verwendet wird die Technik des dynamischen Scopings
Meinung von GN⁺
-
Ein interessanter Versuch, die homoikonische Eigenschaft von Lisp in Python nachzuahmen. Dennoch scheint es Grenzen zu geben, die Eigenheiten von Lisp vollständig zu übertragen. Wer den Reiz von Lisp erleben möchte, lernt am besten Lisp selbst.
-
Es ist beeindruckend, dass starke Lisp-Funktionen wie Lambda-Funktionen und dynamisches Scoping in Python umgesetzt wurden. Für den Einsatz in realen Projekten scheint es jedoch an vielen Stellen noch zu fehlen. Für Lehr- oder Forschungszwecke wirkt es wertvoll.
-
Schon ein solcher Versuch kann ein Anlass sein, grundlegend über das Wesen von Programmiersprachen nachzudenken. Unabhängig von Syntax und Implementierung eröffnet er eine Perspektive auf Programmierparadigmen.
-
Das Lernen einer Lisp-Familien-Sprache kann helfen, Einsichten in funktionale Programmierung und Metaprogrammierung zu gewinnen. Es lohnt sich auch, moderne Lisp-Sprachen wie Scheme, Clojure oder Racket anzusehen.
1 Kommentare
Ein in Python eingebetteter Lisp-Dialekt
https://hylang.org/