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!