Hat Lisp noch eine Besonderheit, die NICHT von anderen Programmiersprachen übernommen wurde?

35

Hat Lisp noch eine Besonderheit, die NICHT von anderen Programmiersprachen übernommen wurde?

Mit Lisp meine ich alle Lisp-Programmiersprachen als Ganzes. Mir wurde gesagt, wie großartig Lisp ist und ich weiß, dass viele Sprachen von Lisp inspiriert wurden. Aber hat Lisp noch ein exklusives Designmerkmal, das in keiner anderen Sprache möglich ist?

Der Grund, warum ich die Frage gestellt habe, ist, dass ich vor kurzem als Amateurprogrammierer angefangen habe, Clojure nur zum Spaß zu lernen , und das Ergebnis ist, dass ich viele Posts und Kommentare zu Lisp gefunden habe, die nur eines sagen: "Lisp ist einzigartig ", aber andere moderne Programmiersprachen haben Lisp bereits viele Ideen abgenommen und gestohlen, darunter Bedingungen, Rekursion und die Funktion als erstklassiger Bürger. Und selbst Metaprogrammierungen können in vielen Sprachen durchgeführt werden.

Habe ich etwas verpasst und ist "Lisp immer noch anders"?

Oder ich habe Glück, weil andere moderne Sprachen alle guten Teile von Lisp gestohlen haben, so dass es nicht notwendig ist, in die Welt von Lisp in Klammern zu graben , und "Lisp war anders".

iceX
quelle
3
Das Teilen Ihrer Forschung hilft allen. Sagen Sie uns, was Sie versucht haben und warum es nicht Ihren Bedürfnissen entsprach. Dies zeigt, dass Sie sich die Zeit genommen haben, um sich selbst zu helfen, es erspart uns, offensichtliche Antworten zu wiederholen, und vor allem hilft es Ihnen, eine spezifischere und relevantere Antwort zu erhalten. Siehe auch Wie man fragt
Mücke
3
@gnat Thx um Rat, und ich habe meine Frage aktualisiert :)
iceX
10
Ein Problem ist, dass die Leute behaupten, eine Sprache sei ein Lisp, sobald sie eine bestimmte Teilmenge von Lisp-Funktionen (z. B. S-Ausdrücke und Makros) hat. Was natürlich zur Folge hat, dass (diesen Leuten zufolge) keine Nicht-Lisp-Sprache diese Eigenschaften haben kann.
9
Ich denke, es gibt keine andere Sprache, in der runde Klammern die einzige Form der Gruppierung für alles sind :-)
Doc Brown
Lisp als Familie mag nicht besonders einzigartig sein, aber viele Lisp-Dialekte (Racket, CL, Scheme, Clojure) bieten immer noch viele nützliche / einzigartige Funktionen.
Daniel Gratzer

Antworten:

28

Eine kanonische Referenz für diese Art von Fragen ist Paul Grahams What Made Lisp Different . Die beiden verbleibenden Hauptmerkmale von Lisp, die laut diesem Artikel zum Zeitpunkt seines Schreibens nicht allgemein verfügbar sind, sind:

8. Eine Notation für Code unter Verwendung von Symbolbäumen.

9. Die ganze Sprache immer verfügbar. Es gibt keinen wirklichen Unterschied zwischen Lesezeit, Kompilierzeit und Laufzeit. Sie können während des Lesens Code kompilieren oder ausführen, während des Kompilierens Code lesen oder ausführen und zur Laufzeit Code lesen oder kompilieren.

Der Kommentar spricht jeden Punkt an und nennt beliebte Sprachen, in denen diese Funktion verfügbar ist.

8, was (mit 9) Lisp-Makros ermöglicht, ist bislang nur für Lisp verfügbar, vielleicht weil (a) diese Parens oder etwas genauso Schlechtes erforderlich sind, und (b) wenn Sie dieses letzte Leistungsinkrement hinzufügen Sie können nicht länger behaupten, eine neue Sprache erfunden zu haben, sondern nur einen neuen Lisp-Dialekt entworfen zu haben; -)

Beachten Sie, dass dieser Artikel zuletzt im Jahr 2002 überarbeitet wurde und in den letzten 11 Jahren eine Vielzahl neuer Sprachen hinzugekommen ist, von denen einige möglicherweise alle diese Lisp-Funktionen in ihren Entwurf einbeziehen.

Greg Hewgill
quelle
2
Diese Funktionen sind nicht nur für Lisp (und direkt abgeleitete Varianten) verfügbar, und das schon seit geraumer Zeit.
Donal Fellows
21
@iceX: Der Unterschied zwischen JavaScript und Sprachen wie Lisp, Smalltalk, Self, Newspeak, APL, Factor, Forth usw. besteht darin, dass in JavaScript Programme "tot" sind. Sie sind Textdateien. Sie beenden das laufende Programm, bearbeiten die Textdatei und starten dann eine vollständig neue Kopie des Programms. In diesen anderen (sogenannten "lebhaften" Umgebungen) beenden Sie niemals das laufende Programm. Das laufende Programm selbst besteht aus einer Reihe von Objekten im Speicher, die Sie genauso bearbeiten, wie Sie jedes andere Objekt bearbeiten, während es ausgeführt wird . (Hinweis: Dies gilt nicht für Clojure, aber die meisten älteren Lisps tun dies auf diese Weise.)
Jörg W Mittag
2
@ JörgWMittag Wow ... Also, Programmiersprachen wie Clojure, Clojurescript, Lispyscript sind in der Tat nicht "echtes Lisp", weil sie ihren Code nicht so ändern können, wie es das alte Lisp tut, wie es Common Lisp tut. Aber ... wenn sie es nicht ändern können ... warum sollten sie sich die Mühe machen, den S-Ausdruck zu verwenden, den ich für den Zweck der
Codemanipulation hielt
4
@iceX: Viele Sprachen haben evaloder ähnliches, und einige können Metaprogramme erstellen , z. B. Haskells Template Haskell. Das (wohl) Einzigartige an Lisp ist, dass die Repräsentation für Daten, Code und Meta-Code identisch ist - nicht nur in der Syntax, sondern es ist wirklich dasselbe.
Tdammers
2
@iceX Eval ist nur ein Teil davon, aber nicht alles. In Lisp können Sie Code zur Kompilierungszeit ausführen. Sie können Code zum Zeitpunkt des Lesens ausführen. Ja, clojure unterstützt die gesamte Dynamik von Lisp. Es verfügt über Makros, Reader-Makros und Eval sowie die Möglichkeit, eine REPL an ein laufendes Programm anzuhängen, um es im laufenden Betrieb zu ändern.
Stonemetal
15

Die Frage ist schwierig zu beantworten, da jemand alle Sprachen beherrschen muss, um zu wissen, dass in Lisp keine andere Sprache über eine bestimmte Funktion verfügt. Daher basiert das Folgende auf den Sprachen, mit denen ich Erfahrung habe.

Aus der Spitze von meinem Kopf, Bedingungen sind etwas , dass ich nicht in einer anderen Sprache , gesehen habe. Denken Sie an "Ausnahmen", bei denen der Aufrufstapel nicht abgewickelt wird und bei denen der Aufrufer einen Wiederherstellungswert an die Ausnahmesite senden kann, ohne den Aufrufstapel zwischen dem Handler und der Quelle der Ausnahme zu stören. Um fair zu sein, das ist wirklich nur eine spezielle Anwendung von Fortsetzungen, so Ruby und Scheme (mindestens) kann dies tun.

Lisps Makrosystem profitiert von Regelmäßigkeit / Homoikonizität, aber Scala plant, sie als stabiles Feature in 2.12 aufzunehmen, und Template Haskell behauptet, ähnliche Features zu haben. Ich würde argumentieren, dass sie syntaktisch komplexer sind als mit Lisp, aber die Generierung von Code während der Kompilierung ist trotzdem vorhanden.

Wenn Sie sich das vorstellen, ist das direkte Bauen von Formularen in Lisp nur eine Art von Makro: Ich habe nirgendwo anders ein Äquivalent von Compiler- oder Reader-Makros gesehen.

Die Fähigkeit einiger Dialekte (z. B. SBCL ), ein vollständiges, wiederaufnahmefähiges Prozessabbild zu speichern, ist cool, aber auch dies ist kein Einzelfall: Smalltalk tut dies seit Jahrzehnten.

In vielen anderen Sprachen ist die Zuweisung von Destrukturierungen bei der Rückgabe von Arrays möglich, aber der Ansatz # 'values ​​und #' multiple-value-bind / let-values ​​scheint immer noch spezifisch für Common Lisp und Scheme zu sein (die auch noch 'reguläre' Destrukturierungen durchführen können ). Perls 'wantarray' ermöglicht es einer Funktion, zu bestimmen, ob sie in einem skalaren, Listen- oder ungültigen Kontext aufgerufen wird, damit ihr Rückgabewert auf ähnliche (-ish) Weise angepasst werden kann, aber ich habe nicht gesehen, dass mehrere Rückgabewerte "wahr" sind of Scheme / CL.

In Bezug auf den Sprachfunktionen, gibt es wahrscheinlich nicht viel , dass Lisp kann tun , dass andere Sprachen nicht (Turing Vollständigkeit zu sein , was es ist). Was es ist , jedoch ist eine Sprache , wo der Code in Bezug auf seine eigenen Datenstrukturen zum Ausdruck kommt, so dass der Big Idea ™ -Das Code Daten etwas , das mit zur Arbeit relativ einfach ist.

Danny Woods
quelle
3
Scala-Makros sind viel weniger leistungsfähig als Lisp-Makros sowie TH-Makros, Schema-Hygienemakros usw. Ein ebenso leistungsfähiges System finden Sie in MetaLua und Converge.
SK-logic
4

Nach so vielen Jahrzehnten glaube ich, dass es nichts Exklusives für Lisp gibt. Aber auch heute noch gibt es viele interessante Dinge, die außerhalb von Lisps schwer zu finden sind. Ein paar Dinge, die mir einfallen:

  • Ein qualitativ hochwertiges Objektsystem mit ausgefeilten Meta-Protokollen (dh CLOS) ist nicht im entferntesten populär.
  • Multi-Methoden tauchen von Zeit zu Zeit irgendwo auf, aber die meisten Leute haben noch nie davon gehört.
  • Wie andere bereits betont haben, ist das Konditionssystem im Vergleich zu gängigen Ausnahmebehandlungsmechanismen recht ausgefeilt.
  • Eine kompakte Darstellung der Semantik der Sprache (eval), ein befähigender Ansatz, die eigene Sprache zu definieren und für einfache, tiefgreifende Anpassungen zur Verfügung zu stellen (siehe SICP ) - "eval" -Funktionen aktueller populärer Sprachen haben einfach nicht dieselben Eigenschaften.

Schließlich gibt es noch viel mehr von Lisp zu lernen, das sich nicht mit der Sprache selbst befasst, sondern Teil der Lisp-Geschichte wurde und sich mit der Zeit verirrt hat. ZB Interlisp, Symbolics Genera, etc ... Wenn Sie Genera noch nie in die Finger bekommen haben, lesen Sie diesen Thread in comp.lang.lisp, in dem Kent Pitman beschreibt, wie "Emacs nur ein blasser Schatten von Generas Zmacs ist" Ein leistungsstarkes Lisp-System, an dem Zmacs beteiligt war und das auf einer Lisp-Maschine lief.

Thiago Silva
quelle
Ich habe noch nie eine gute Erklärung für Multimethoden gesehen, die sie von überladenen Methoden unterschieden , ein Standardmerkmal in fast jeder modernen imperativen Sprache, außer der Tatsache, dass Multimethodenversand zur Laufzeit dynamisch aufgelöst wird und daher viel langsamer ist als die Verwendung überladener Methoden werden zur Kompilierzeit aufgelöst.
Mason Wheeler
Sie haben wichtige Unterschiede. Wenn Sie Probleme damit haben, eine Ressource zu finden, können Sie hier jederzeit eine neue Frage erstellen.
Thiago Silva
Julia hat Multimethoden, und Haskells parametrischer Polymorphismus ähnelt Multimethoden. Es gibt Möglichkeiten, Multimethoden in vielen Sprachen zu simulieren. Das Konditionssystem ist etwas, das ich wirklich besonders will (editieren und fortsetzen, obwohl ich es für C # -Debugger gesehen habe).
aoeu256
4

Es ist nicht unbedingt eine bestimmte Funktion . Es ist das gesamte Erscheinungsbild und die Funktionsweise bestimmter Funktionen.

JavaScript oder Java verfügen über zahlreiche Funktionen von Lisp (virtuelle Maschine, Compiler / Evaluator, Garbage Collection usw.). Aber JavaScript zum Beispiel fehlt der symbolische Programmierteil, es fehlen mathematische Fähigkeiten (intern hat es nur Gleitkommazahlen), es fehlt die Fehlerbehandlung und so weiter.

Viele gängige Lisp- Systeme sind für eine Entwicklungsmethode optimiert, bei der neue Software schrittweise erweitert wird, indem die Lisp-Sprache in verschiedenen Dimensionen mithilfe verschiedener Meta-Programmiertechniken erweitert wird - ohne dass die Software für längere Zeit neu gestartet werden muss. Daher muss es flexibel und erweiterbar sein - aber gleichzeitig muss es robust sein. Ändern der Sprache (Makros sind im Grunde eine Möglichkeit für den Benutzer, den Compiler zu erweitern), ohne das Programm zum Absturz zu bringen.

So etwas wie JavaScript wird jetzt auch zum Erweitern eines Programms verwendet, normalerweise eines Webbrowsers. Aber die meiste Zeit macht man nicht viel Metaprogrammierung in JavaScript - abgesehen von einigem OOP- Hackery.

Beispiel:

Eine allgemeine fortgeschrittene Mathematik-Software für den Bereich der Computeralgebra kann auf zwei Arten implementiert werden: Schreiben Sie die Engine in C mit einer speziellen Sprache (wie Mathematica ) oder in einem fortgeschritteneren Lisp-Dialekt. Macsyma / Maxima in Common Lisp, Reduce in Standard Lisp, Axiom in Common Lisp.

(Es gibt auch eine oder mehrere in Python.)

Es gibt nicht viele Systeme, die den Funktionsumfang von Axiom bieten , das auf Common Lisp läuft.

Was Lisp für diese Art von Anwendungen attraktiv gemacht hat, ist eine Mischung aus Funktionen: fortgeschrittene grundlegende Mathematik (Bignums, Verhältnisse, ...), symbolische Berechnung, interaktiver Compiler usw. ebene sprache. Auf diese Weise hat man 50% oder mehr eines typischen Lisp-Systems implementiert.

Rainer Joswig
quelle
2

Nicht so weit ich weiß. Forth ist leicht so dynamisch wie Lisp, vielleicht umso mehr, als dynamischer Code in Forth wie normaler Forth-Code aussieht, während Lisp-Makros andere Funktionen als normaler Lisp-Code verwenden ( zumindest in Clojure habe ich kein Syntaxzitat außerhalb eines Makros verwendet) und Infolgedessen sehen sie wirklich anders aus als normaler Lisp-Code. Ein Beispiel für die Dynamik von Forth ist die Implementierung von Kommentaren in Forth :

: (   41 word drop ; immediate
( That was the definition for the comment word. )
( Now we can add comments to what we are doing! )
Steinmetalle
quelle
1
So lustig Forth auch zu sein scheint, ich fand es immer hoffnungslos undurchsichtig und umständlich, vielleicht weil es stapelbasiert ist und alles umgekehrt ist.
Robert Harvey
2
Was meinen Sie aus Neugier mit „vom Hauptteil der Sprache getrennt“? Makros in Lisp haben uneingeschränkten Zugriff auf alle Funktionen, die an dem Punkt definiert sind, an dem das Makro definiert ist. Mit diesen Funktionen kann das Formular erstellt werden, in das das Makro expandiert. Dies kann Informationen beinhalten, die von einer Datenbank und / oder einem Server abgerufen wurden. Ihr Kommentar-Beispiel könnte wie folgt definiert sein: (defmacro comment (& rest body)), nicht wahr?
Danny Woods
1
@DannyWoods Ich meine, Makros sehen nicht wie normaler Code aus. Zumindest in Clojure können Sie Makrocode von normalem Code unterscheiden, da Syntax-Anführungszeichen, Aufheben der Anführungszeichen usw. verwendet werden, was in normalem Code ungewöhnlich ist. Der Beispielcode, den ich gegeben habe, sieht aus wie normaler Code, bis Sie den unmittelbaren Code sehen. Als ich meine Antwort noch einmal las, drückte es sich nur schlecht aus.
Stonemetal
1
@stonemetal Keine Sorge, aber es ist erwähnenswert, dass das Syntaxzitat weder in Common Lisp noch in Clojure makrospezifisch ist. Manchmal ist es praktisch, Backtick-Ausdrücke in regulären Funktionsdefinitionen zu haben, und Makrokörper können manuell mit einfachen Listen erstellt werden (obwohl Sie dies nur ein- oder zweimal tun müssen, um zu entscheiden, dass das Syntaxzitat eine gute Sache ist!)
Danny Woods
1
Um fair zu sein, können Sie dasselbe in Lisp tun, indem Sie ein benutzerdefiniertes Reader-Makro registrieren.
Fjarri
2

Lisp hat viele Dialekte und jeder von ihnen hat seine eigenen Funktionen. Mein Lieblingsfeature, das wahrscheinlich von keiner anderen Sprache übernommen wird, ist der "Spaghetti Stack" von Interlisp .

Der Spaghetti-Stapel ist wie ein Verschluss, aber auf Steroiden. Es speichert nicht nur die aktuelle Funktion, sondern den gesamten Kontext bis zum Anfang des Stapels. Eine Art Co-Routine , mit der Ausnahme, dass Sie diese beliebig erstellen können, was zu einer Hierarchie von Stapelkontexten führt.

ddyer
quelle
Wusste nicht, werde es überprüfen, danke für Ihre Antwort :)
iceX
7
Ist dies dasselbe wie die Fortsetzungen von Schema?
Nicola Musatti
1
@NicolaMusatti, ein "Spaghetti Stack", ist eine gängige Implementierungsstrategie für schemaähnliche Fortsetzungen (die aufgerufen werden kann, nachdem die Funktion, die sie erstellt hat, zurückgegeben wurde).
Alex D