Kurze Antwort
Bypass die Bewertungsregeln Ausfall- und tut nicht bewertet den Ausdruck (Symbol oder s-exp), vorbei entlang auf die Funktion genau wie eingegeben.
Lange Antwort: Die Standardbewertungsregel
Wenn eine reguläre Funktion (darauf komme ich später zurück) aufgerufen wird, werden alle an sie übergebenen Argumente ausgewertet. Dies bedeutet, dass Sie Folgendes schreiben können:
(* (+ a 2)
3)
Was wiederum (+ a 2)
durch Auswertung a
und 2 ausgewertet wird . Der Wert des Symbols a
wird im aktuellen Variablenbindungssatz nachgeschlagen und dann ersetzt. Say a
ist derzeit an den Wert 3 gebunden:
(let ((a 3))
(* (+ a 2)
3))
Wir würden bekommen (+ 3 2)
, + wird dann auf 3 und 2 aufgerufen, was 5 ergibt. Unsere ursprüngliche Form ergibt jetzt (* 5 3)
15.
Erklären Sie quote
bereits!
In Ordung. Wie oben gezeigt, werden alle Argumente für eine Funktion ausgewertet. Wenn Sie also das Symbol a
und nicht seinen Wert übergeben möchten, möchten Sie es nicht auswerten. Lisp-Symbole können sowohl als Werte als auch als Markierungen verwendet werden, bei denen Sie in anderen Sprachen Zeichenfolgen verwendet hätten, z. B. Schlüssel für Hash-Tabellen.
Hier quote
kommt das Spiel ins Spiel. Angenommen, Sie möchten Ressourcenzuweisungen aus einer Python-Anwendung zeichnen, aber das Zeichnen in Lisp durchführen. Lassen Sie Ihre Python-App etwa Folgendes tun:
print("'(")
while allocating:
if random.random() > 0.5:
print(f"(allocate {random.randint(0, 20)})")
else:
print(f"(free {random.randint(0, 20)})")
...
print(")")
Geben Sie Ihre Ausgabe so (leicht hübsch):
'((allocate 3)
(allocate 7)
(free 14)
(allocate 19)
...)
Erinnern Sie sich, was ich über quote
("Häkchen") gesagt habe, wodurch die Standardregel nicht angewendet wurde? Gut. Was sonst passieren würde, ist, dass die Werte von allocate
und free
nachgeschlagen werden, und das wollen wir nicht. In unserem Lisp möchten wir Folgendes tun:
(dolist (entry allocation-log)
(case (first entry)
(allocate (plot-allocation (second entry)))
(free (plot-free (second entry)))))
Für die oben angegebenen Daten wäre die folgende Folge von Funktionsaufrufen durchgeführt worden:
(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)
Aber was ist mit list
?
Nun, manchmal Sie tun wollen , die Argumente zu bewerten. Angenommen, Sie haben eine raffinierte Funktion, die eine Zahl und eine Zeichenfolge bearbeitet und eine Liste der resultierenden ... Dinge zurückgibt. Machen wir einen Fehlstart:
(defun mess-with (number string)
'(value-of-number (1+ number) something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING))
Hallo! Das wollten wir nicht. Wir wollen einige Argumente selektiv bewerten und die anderen als Symbole belassen. Versuchen Sie # 2!
(defun mess-with (number string)
(list 'value-of-number (1+ number) 'something-with-string (length string)))
Lisp> (mess-with 20 "foo")
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3)
Nicht nur quote
, sondernbackquote
Viel besser! Übrigens ist dieses Muster in (meistens) Makros so häufig, dass es dafür eine spezielle Syntax gibt. Das Backquote:
(defun mess-with (number string)
`(value-of-number ,(1+ number) something-with-string ,(length string)))
Es ist wie mit quote
, aber mit der Option, einige Argumente explizit auszuwerten, indem ihnen ein Komma vorangestellt wird. Das Ergebnis entspricht der Verwendung list
. Wenn Sie jedoch Code aus einem Makro generieren, möchten Sie häufig nur kleine Teile des zurückgegebenen Codes auswerten, sodass das Backquote besser geeignet ist. list
Kann für kürzere Listen besser lesbar sein.
Hey, du hast es vergessen quote
!
Wo bleibt uns das? Oh richtig, was macht quote
eigentlich? Es gibt einfach seine Argumente zurück, die nicht bewertet wurden! Erinnerst du dich, was ich am Anfang über reguläre Funktionen gesagt habe? Es stellt sich heraus, dass einige Operatoren / Funktionen ihre Argumente nicht bewerten müssen. Zum Beispiel IF - Sie möchten nicht, dass der Zweig else ausgewertet wird, wenn er nicht verwendet wird, oder? So arbeiten sogenannte Spezialoperatoren zusammen mit Makros. Spezielle Operatoren sind auch das "Axiom" der Sprache - minimale Regeln -, nach denen Sie den Rest von Lisp implementieren können, indem Sie sie auf unterschiedliche Weise miteinander kombinieren.
Zurück zu quote
:
Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL
Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL
Vergleiche mit (auf Steel-Bank Common Lisp):
Lisp> spiffy-symbol
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING {A69F6A9}>:
The variable SPIFFY-SYMBOL is unbound.
Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [ABORT] Exit debugger, returning to top level.
(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>)
0]
Weil es spiffy-symbol
im aktuellen Umfang keine gibt !
Zusammenfassen
quote
, backquote
(mit Komma) und list
sind einige der Werkzeuge, die Sie zum Erstellen von Listen verwenden. Dies sind nicht nur Wertelisten, sondern können, wie Sie gesehen haben, als einfache struct
Datenstrukturen verwendet werden (Sie müssen keine definieren )!
Wenn Sie mehr erfahren möchten, empfehle ich Peter Seibels Buch Practical Common Lisp für einen praktischen Ansatz zum Erlernen von Lisp, wenn Sie bereits mit dem Programmieren auf freiem Fuß beschäftigt sind. Schließlich werden Sie auf Ihrer Lisp-Reise auch Pakete verwenden. Ron Garrets The Idiot's Guide zu gängigen Lisp-Paketen gibt Ihnen eine gute Erklärung dafür.
Viel Spaß beim Hacken!
this
, dannis
, danntrue
, aber nur die letzten zurück sehen. (Dies ist und wahr sind separate Aussagen)Es heißt "bewerte mich nicht". Wenn Sie beispielsweise eine Liste als Daten und nicht als Code verwenden möchten, setzen Sie ein Zitat davor. Beispielsweise,
(print '(+ 3 4))
druckt "(+ 3 4)", während(print (+ 3 4))
"7"quelle
unquote
Befehl?eval
:(print (eval '(+ 3 4)))
. Dies macht Lisps so großartig: Listen sind Code und Code sind Listen, sodass ein Lisp-Programm sich selbst manipulieren kann.Andere Leute haben diese Frage bewundernswert beantwortet, und Matthias Benkard bringt eine ausgezeichnete Warnung vor.
Verwenden Sie kein Zitat, um Listen zu erstellen, die Sie später ändern werden. Die Spezifikation ermöglicht es dem Compiler, Listen in Anführungszeichen als Konstanten zu behandeln. Oft optimiert ein Compiler Konstanten, indem er einen einzelnen Wert für sie im Speicher erstellt und dann von allen Stellen, an denen die Konstante angezeigt wird, auf diesen einzelnen Wert verweist. Mit anderen Worten, es kann die Konstante wie eine anonyme globale Variable behandeln.
Dies kann offensichtliche Probleme verursachen. Wenn Sie eine Konstante ändern, können möglicherweise auch andere Verwendungen derselben Konstante in völlig unabhängigem Code geändert werden. Sie können beispielsweise eine Variable in einer Funktion mit '(1 1) vergleichen und in einer völlig anderen Funktion eine Liste mit' (1 1) beginnen und dann weitere Elemente hinzufügen. Wenn Sie diese Funktionen ausführen, stellen Sie möglicherweise fest, dass die erste Funktion nicht mehr richtig übereinstimmt, da jetzt versucht wird, die Variable mit '(1 1 2 3 5 8 13) zu vergleichen, was die zweite Funktion zurückgegeben hat. Diese beiden Funktionen sind völlig unabhängig voneinander, wirken sich jedoch aufgrund der Verwendung von Konstanten gegenseitig aus. Sogar verrücktere schlechte Effekte können auftreten, wie eine ganz normale Listeniteration, die plötzlich eine Endlosschleife aufweist.
Verwenden Sie das Anführungszeichen, wenn Sie eine konstante Liste benötigen, z. B. zum Vergleich. Verwenden Sie die Liste, wenn Sie das Ergebnis ändern möchten.
quelle
(list (+ 1 2))
meiste Zeit verwenden sollten. Wenn ja, wie verhindern Sie die Bewertung eines(+ 1 2)
solchen Beispiels? Gibt es einenunquote
Befehl?'((3))
oder das Äquivalent von'((+ 1 2))
? In letzterem Fall müssen Sie mehr verwendenlist
:(list (list '+ 1 2))
. Oder wenn Sie das Äquivalent von'(+ 1 2)
nur wollten(list '+ 1 2)
. Und denken Sie daran, wenn Sie die Liste nicht ändern, können Sie auch das Zitat verwenden: Es ist nichts Falsches daran, wenn Sie nur mit der Liste'(+ 1 2)
vergleichen oder so.Eine Antwort auf diese Frage besagt, dass QUOTE „Listendatenstrukturen erstellt“. Das ist nicht ganz richtig. QUOTE ist grundlegender als dies. Tatsächlich ist QUOTE ein trivialer Operator: Er soll verhindern , dass überhaupt etwas passiert. Insbesondere schafft es nichts.
Was (ZITAT X) sagt, ist im Grunde: "Tu nichts, gib mir nur X." X muss keine Liste wie in (QUOTE (ABC)) oder ein Symbol wie in (QUOTE FOO) sein. Es kann jedes Objekt sein, was auch immer. In der Tat gibt das Ergebnis der Auswertung der Liste, die von (LIST 'QUOTE SOME-OBJECT) erstellt wurde, immer nur SOME-OBJECT zurück, was auch immer es ist.
Der Grund, warum (QUOTE (ABC)) so aussieht, als hätte es eine Liste erstellt, deren Elemente A, B und C sind, ist, dass eine solche Liste wirklich das ist, was sie zurückgibt. Zum Zeitpunkt der Auswertung des QUOTE-Formulars existiert die Liste jedoch im Allgemeinen bereits seit einiger Zeit (als Bestandteil des QUOTE-Formulars!) und wurde entweder vom Loader oder vom Reader vor der Ausführung des Codes erstellt.
Eine Implikation davon, die Neulinge ziemlich oft auslöst, ist, dass es sehr unklug ist, eine von einem QUOTE-Formular zurückgegebene Liste zu ändern. Von QUOTE zurückgegebene Daten sind in jeder Hinsicht als Teil des ausgeführten Codes zu betrachten und sollten daher als schreibgeschützt behandelt werden!
quelle
Das Zitat verhindert die Ausführung oder Auswertung eines Formulars und wandelt es stattdessen in Daten um. Im Allgemeinen können Sie die Daten ausführen, indem Sie sie dann auswerten.
Zitat erstellt Listendatenstrukturen, zum Beispiel sind die folgenden äquivalent:
Es kann auch zum Erstellen von Listen (oder Bäumen) verwendet werden:
Am besten holen Sie sich ein Einführungsbuch über Lisp, wie z. B. Practical Common Lisp (das online gelesen werden kann).
quelle
In Emacs Lisp:
Was kann zitiert werden?
Listen und Symbole.
Das Zitieren einer Nummer ergibt die Nummer selbst:
'5
ist dasselbe wie5
.Was passiert, wenn Sie Listen zitieren?
Beispielsweise:
'(one two)
bewertet zu(list 'one 'two)
was zu bewertet(list (intern "one") (intern ("two")))
.(intern "one")
Erstellt ein Symbol mit dem Namen "Eins" und speichert es in einer "zentralen" Hash-Map. Wenn Sie also sagen,'one
wird das genannte Symbol"one"
in dieser zentralen Hash-Map nachgeschlagen.Aber was ist ein Symbol?
Beispielsweise könnte in OO-Sprachen (Java / Javascript / Python) ein Symbol als ein Objekt dargestellt werden, das ein
name
Feld hat, das der Name des Symbols wie"one"
oben ist, und diesem Objekt können Daten und / oder Code zugeordnet werden.Ein Symbol in Python könnte also wie folgt implementiert werden:
In Emacs Lisp kann beispielsweise einem Symbol 1) Daten zugeordnet sein UND (gleichzeitig - für dasselbe Symbol) 2) Code zugeordnet werden - je nach Kontext werden entweder die Daten oder der Code aufgerufen.
Zum Beispiel in Elisp:
bewertet zu
4
.Weil
(add add add)
bewertet als:Mit der
Symbol
Klasse, die wir oben in Python definiert haben, könnte diesesadd
ELisp-Symbol beispielsweise in Python als geschrieben werdenSymbol("add",(lambda x,y: x+y),2)
.Vielen Dank für die Leute im IRC #emacs, die mir Symbole und Zitate erklärt haben.
quelle
Wenn wir ein Argument selbst übergeben möchten, anstatt den Wert des Arguments zu übergeben, verwenden wir das Anführungszeichen. Es hängt hauptsächlich mit der Prozedur zusammen, die während der Verwendung von Listen, Paaren und Atomen ausgeführt wird, die in der Programmiersprache C nicht verfügbar sind (die meisten Leute beginnen mit der Programmierung in der Programmiersprache C, daher werden wir verwirrt). Dies ist Code in der Programmiersprache Schema, der ein Dialekt von lisp ist und ich denke, Sie können diesen Code verstehen.
Die letzte Zeile (atom? 'Abc) übergibt abc wie an die Prozedur, um zu überprüfen, ob abc ein Atom ist oder nicht. Wenn Sie jedoch übergeben (atom? Abc), prüft sie den Wert von abc und übergibt den Wert an es. Seitdem haben wir keinen Wert dafür angegeben
quelle
Quote gibt die interne Darstellung seiner Argumente zurück. Nachdem zu viele Erklärungen durchgearbeitet wurden, was das Zitat nicht tut, ging die Glühbirne an. Wenn die REPL beim Zitieren keine Funktionsnamen in UPPER-CASE konvertiert hätte, wäre es mir möglicherweise nicht aufgefallen.
So. Gewöhnliche Lisp-Funktionen konvertieren ihre Argumente in eine interne Darstellung, werten die Argumente aus und wenden die Funktion an. Quote konvertiert seine Argumente in eine interne Darstellung und gibt diese nur zurück. Technisch ist es richtig zu sagen, dass das Zitat "nicht bewerten" sagt, aber als ich versuchte zu verstehen, was es tat, war es frustrierend, mir zu sagen, was es nicht tut. Mein Toaster bewertet auch keine Lisp-Funktionen. Aber so erklären Sie nicht, was ein Toaster tut.
quelle
Eine weitere kurze Antwort:
quote
bedeutet, ohne es zu bewerten, und backquote ist Zitat, aber lassen Sie Hintertüren .Eine gute Referenz:
Das Emacs Lisp Referenzhandbuch macht es sehr deutlich
9.3 Zitieren
Das spezielle Formularzitat gibt sein einzelnes Argument wie geschrieben zurück, ohne es zu bewerten. Dies bietet die Möglichkeit, konstante Symbole und Listen, die keine selbstbewertenden Objekte sind, in ein Programm aufzunehmen. (Es ist nicht erforderlich, selbstbewertende Objekte wie Zahlen, Zeichenfolgen und Vektoren anzugeben.)
Sonderform: Angebotsobjekt
Da Anführungszeichen in Programmen so häufig verwendet werden, bietet Lisp eine bequeme Lesesyntax. Ein Apostrophzeichen ('' ') gefolgt von einem Lisp-Objekt (in Lesesyntax) wird zu einer Liste erweitert, deren erstes Element in Anführungszeichen und deren zweites Element das Objekt ist. Somit ist die Lesesyntax 'x eine Abkürzung für (Zitat x).
Hier sind einige Beispiele für Ausdrücke, die Anführungszeichen verwenden:
9.4 Backquote
Mit Backquote-Konstrukten können Sie eine Liste zitieren, aber Elemente dieser Liste selektiv auswerten. Im einfachsten Fall ist es identisch mit dem speziellen Formularzitat (im vorherigen Abschnitt beschrieben; siehe Zitat). Zum Beispiel liefern diese beiden Formen identische Ergebnisse:
Die spezielle Markierung ',' innerhalb des Arguments to backquote gibt einen Wert an, der nicht konstant ist. Der Emacs Lisp-Evaluator wertet das Argument ',' aus und fügt den Wert in die Listenstruktur ein:
Die Ersetzung durch ',' ist auch auf tieferen Ebenen der Listenstruktur zulässig. Beispielsweise:
Sie können einen ausgewerteten Wert auch mit der speziellen Markierung ', @' in die resultierende Liste einfügen. Die Elemente der gespleißten Liste werden zu Elementen auf derselben Ebene wie die anderen Elemente der resultierenden Liste. Der entsprechende Code ohne Verwendung von '`' ist häufig nicht lesbar. Hier sind einige Beispiele:
quelle
Dies ist eine klassische Aussage, die jeder Lisp-Programmierer kennt.
Wenn Sie einen Code zitieren, handelt es sich bei diesem Code um Daten.
Wenn Sie einen Code zitieren, sind das Ergebnis Daten, die diesen Code darstellen. Wenn Sie also mit Daten arbeiten möchten, die ein Programm darstellen, zitieren Sie dieses Programm. Dies gilt auch für atomare Ausdrücke, nicht nur für Listen:
Angenommen, Sie möchten eine in lisp eingebettete Programmiersprache erstellen - Sie arbeiten mit Programmen, die im Schema (wie
'(+ 2 3)
) zitiert sind und in der von Ihnen erstellten Sprache als Code interpretiert werden, indem Sie Programmen eine semantische Interpretation geben. In diesem Fall müssen Sie ein Anführungszeichen verwenden, um die Daten zu speichern. Andernfalls werden sie in einer externen Sprache ausgewertet.quelle