Ist eine statisch typisierte vollständige Lisp-Variante möglich? Ist es überhaupt sinnvoll, dass so etwas existiert? Ich glaube, eine der Tugenden einer Lisp-Sprache ist die Einfachheit ihrer Definition. Würde statische Typisierung dieses Kernprinzip beeinträchtigen?
programming-languages
lisp
static-typing
Lambda der Vorletzte
quelle
quelle
Antworten:
Ja, das ist sehr gut möglich, obwohl ein Standard-HM-System normalerweise die falsche Wahl für den meisten idiomatischen Lisp / Scheme-Code ist. Unter Typed Racket finden Sie eine aktuelle Sprache, die ein "Full Lisp" (eigentlich eher wie "Scheme") mit statischer Typisierung ist.
quelle
Sexpr
.coerce :: a->b
in Bezug auf die Bewertung schreiben . Wo ist die Typensicherheit?eval
Sie das Ergebnis testen müssen, um zu sehen, was herauskommt, was in Typed Racked nichts Neues ist (dasselbe Angebot wie bei einer Funktion, die einen Union-Typ vonString
und verwendetNumber
). Ein impliziter Weg, um zu sehen, dass dies möglich ist , ist die Tatsache, dass Sie eine dynamisch typisierte Sprache in einer HM-statisch typisierten Sprache schreiben und verwenden können .Wenn Sie nur eine statisch typisierte Sprache wollten, die wie Lisp aussah , können Sie dies ziemlich einfach tun, indem Sie einen abstrakten Syntaxbaum definieren, der Ihre Sprache darstellt, und diesen AST dann S-Ausdrücken zuordnen. Ich glaube jedoch nicht, dass ich das Ergebnis Lisp nennen würde.
Wenn Sie etwas möchten, das neben der Syntax auch Lisp-y-Eigenschaften aufweist, können Sie dies mit einer statisch typisierten Sprache tun. Es gibt jedoch viele Eigenschaften von Lisp, aus denen sich nur schwer nützliche statische Eingaben ableiten lassen. Schauen wir uns zur Veranschaulichung die Listenstruktur selbst an, die als Nachteile bezeichnet wird und den Hauptbaustein von Lisp bildet.
Die Nachteile als Liste zu bezeichnen, obwohl es so
(1 2 3)
aussieht, ist eine Fehlbezeichnung. Zum Beispiel ist es überhaupt nicht vergleichbar mit einer statisch typisierten Liste wie der von C ++std::list
oder Haskell. Dies sind eindimensionale verknüpfte Listen, in denen alle Zellen vom gleichen Typ sind. Lisp erlaubt gerne(1 "abc" #\d 'foo)
. Selbst wenn Sie Ihre statisch typisierten Listen auf Listenlisten erweitern, erfordert der Typ dieser Objekte, dass jedes Element der Liste eine Unterliste ist. Wie würden Sie((1 2) 3 4)
in ihnen vertreten?Lisp-Konsen bilden einen binären Baum mit Blättern (Atomen) und Zweigen (Konsen). Außerdem können die Blätter eines solchen Baumes überhaupt einen atomaren (Nicht-Nachteile) Lisp-Typ enthalten! Die Flexibilität dieser Struktur macht Lisp so gut im Umgang mit symbolischen Berechnungen, ASTs und der Transformation von Lisp-Code selbst!
Wie würden Sie eine solche Struktur in einer statisch typisierten Sprache modellieren? Versuchen wir es in Haskell, das über ein äußerst leistungsfähiges und präzises statisches Typsystem verfügt:
Ihr erstes Problem wird der Umfang des Atom-Typs sein. Es ist klar, dass wir keinen Atom-Typ mit ausreichender Flexibilität ausgewählt haben, um alle Arten von Objekten abzudecken, die wir in Kegeln herumschleudern möchten. Anstatt zu versuchen, die Atom-Datenstruktur wie oben aufgeführt zu erweitern (was Sie deutlich sehen können, ist spröde), nehmen wir an, wir hatten eine magische Typklasse
Atomic
, die alle Typen unterschied, die wir atomar machen wollten. Dann könnten wir versuchen:Dies funktioniert jedoch nicht, da alle Atome im Baum vom gleichen Typ sein müssen. Wir möchten, dass sie sich von Blatt zu Blatt unterscheiden können. Ein besserer Ansatz erfordert die Verwendung von Haskells existenziellen Quantifizierern :
Aber jetzt kommen Sie zum Kern der Sache. Was kann man mit Atomen in dieser Art von Struktur machen? Welche Struktur haben sie gemeinsam, mit der modelliert werden könnte
Atomic a
? Welches Maß an Typensicherheit ist Ihnen bei einem solchen Typ garantiert? Beachten Sie, dass wir unserer Typklasse keine Funktionen hinzugefügt haben, und es gibt einen guten Grund: Die Atome haben in Lisp nichts gemeinsam. Ihr Supertyp in Lisp wird einfacht
(dh oben) genannt.Um sie zu verwenden, müssten Sie Mechanismen entwickeln, um den Wert eines Atoms dynamisch auf etwas zu zwingen, das Sie tatsächlich verwenden können. Und zu diesem Zeitpunkt haben Sie im Grunde ein dynamisch typisiertes Subsystem in Ihrer statisch typisierten Sprache implementiert! (Man kann nicht anders, als eine mögliche Folge von Greenspuns zehnter Programmierregel zu bemerken .)
Beachten Sie, dass Haskell ein solches dynamisches Subsystem mit einem
Obj
Typ unterstützt, der in Verbindung mit einemDynamic
Typ und einer typisierbaren Klasse verwendet wird , um unsereAtomic
Klasse zu ersetzen , sodass beliebige Werte mit ihren Typen gespeichert werden können, und expliziten Zwang von diesen Typen zurückzwingt . Dies ist die Art von System, die Sie benötigen würden, um mit Lisp-Cons-Strukturen in ihrer vollen Allgemeinheit zu arbeiten.Sie können auch in die andere Richtung gehen und ein statisch typisiertes Subsystem in eine im Wesentlichen dynamisch typisierte Sprache einbetten. Dies bietet Ihnen den Vorteil einer statischen Typprüfung für die Teile Ihres Programms, die strengere Typanforderungen nutzen können. Dies scheint der Ansatz zu sein, der beispielsweise in der begrenzten Form der präzisen Typprüfung von CMUCL verfolgt wird .
Schließlich besteht die Möglichkeit, zwei separate Subsysteme zu haben, die dynamisch und statisch typisiert sind und die vertragliche Programmierung verwenden, um den Übergang zwischen beiden zu steuern. Auf diese Weise kann die Sprache die Verwendung von Lisp berücksichtigen, bei der die statische Typprüfung eher ein Hindernis als eine Hilfe darstellt, sowie Anwendungen, bei denen die statische Typprüfung vorteilhaft wäre. Dies ist der Ansatz von Typed Racket , wie Sie den folgenden Kommentaren entnehmen können .
quelle
(Listof Integer)
und(Listof Any)
. Natürlich würden Sie vermuten, dass Letzteres nutzlos ist, weil Sie nichts über den Typ wissen, aber in TR können Sie es später verwenden,(if (integer? x) ...)
und das System wird wissen, dassx
es sich um eine Ganzzahl im 1. Zweig handelt.dynamic
Typen werden in statischen Sprachen als eine Art Problemumgehung immer beliebter, um einige der Vorteile dynamisch typisierter Sprachen zu nutzen, wobei der übliche Kompromiss zwischen diesen Werten so gewickelt wird, dass die Typen identifizierbar sind. Aber auch hier macht getippter Schläger einen sehr guten Job darin, ihn innerhalb der Sprache bequem zu machen - die Typprüfung verwendet das Auftreten von Prädikaten, um mehr über die Typen zu erfahren. Sehen Sie sich beispielsweise das typisierte Beispiel auf der Schlägerseite an und sehen Sie, wiestring?
eine Liste von Zeichenfolgen und Zahlen auf eine Liste von Zeichenfolgen "reduziert" wird.Meine Antwort ohne ein hohes Maß an Vertrauen ist wahrscheinlich . Wenn Sie sich beispielsweise eine Sprache wie SML ansehen und sie mit Lisp vergleichen, ist der Funktionskern jeder Sprache nahezu identisch. Infolgedessen scheint es nicht so, als hätten Sie große Probleme, eine Art statische Typisierung auf den Kern von Lisp anzuwenden (Funktionsanwendung und primitive Werte).
Ihre Frage ist jedoch vollständig , und wo ich sehe, dass einige der Probleme auftreten, ist der Code-as-Data-Ansatz. Typen existieren auf einer abstrakteren Ebene als Ausdrücke. Lisp hat diese Unterscheidung nicht - alles ist "flach" in der Struktur. Wenn wir einen Ausdruck E: T betrachten (wobei T eine Darstellung seines Typs ist) und diesen Ausdruck dann als einfache alte Daten betrachten, was genau ist dann der Typ von T hier? Nun, es ist eine Art! Eine Art ist eine höhere Ordnungsart. Lassen Sie uns also einfach etwas dazu in unserem Code sagen:
Sie könnten sehen, wohin ich damit gehe. Ich bin sicher, dass es durch Trennen der Typinformationen vom Code möglich wäre, diese Art der Selbstreferenzialität von Typen zu vermeiden, aber dies würde die Typen in ihrem Geschmack nicht sehr "lispeln" lassen. Es gibt wahrscheinlich viele Möglichkeiten, dies zu umgehen, obwohl mir nicht klar ist, welche die beste wäre.
EDIT: Oh, also mit ein bisschen googeln habe ich Qi gefunden , das Lisp sehr ähnlich zu sein scheint, außer dass es statisch typisiert ist. Vielleicht ist es ein guter Ort, um zu sehen, wo sie Änderungen vorgenommen haben, um die statische Eingabe dort zu erhalten.
quelle
Dylan: Erweiterung des Dylans-Typsystems für eine bessere Typinferenz und Fehlererkennung
quelle