Réponse courte contourner les règles d'évaluation par défaut et faire pas évaluer l'expression (symbole ou s-exp), en passant le long de la fonction exactement comme tapé.
Réponse longue: La règle d'évaluation par défaut
Lorsqu'une fonction régulière (je reviendrai plus tard) est invoquée, tous les arguments qui lui sont passés sont évalués.Cela signifie que vous pouvez écrire ceci:
(* (+ a 2)
3)
Ce qui, à son tour évalue (+ a 2)
, en évaluant a
et 2. La valeur du symbole a
est recherché dans l'ensemble variable courante de liaison, puis remplacé. Dites a
est actuellement lié à la valeur 3:
(let ((a 3))
(* (+ a 2)
3))
Nous obtiendrions (+ 3 2)
, + est alors invoquée sur 3 et 2 5. Notre rendement forme originale est maintenant (* 5 3)
rendement 15.
Expliquer quote
Déjà!
D'accord. Comme vu ci-dessus, tous les arguments d'une fonction sont évalués, donc si vous voulez passer le symbolea
et non sa valeur, vous ne voulez pas l'évaluer. Les symboles Lisp peuvent doubler en tant que leurs valeurs, et les marqueurs où vous dans d'autres langues auraient utilisé des chaînes, telles que les clés des tables de hachage.
C'est où quote
entre. Dites que vous voulez tracer des allocations de ressources à partir d'une application Python, mais faites plutôt le traçage en Lisp. Demandez à votre application Python faire quelque chose comme ceci:
print "'("
while allocating:
if random.random() > 0.5:
print "(allocate %d)" random.randint(0, 20)
else:
print "(free %d)" % random.randint(0, 20)
...
print ")"
En vous donnant la sortie qui ressemble à ceci (un peu prettyfied):
'((allocate 3)
(allocate 7)
(free 14)
(allocate 19)
...)
Rappelez-vous ce que je disais à propos quote
(« tick ») provoquant la règle par défaut ne appliquer? Bien. Ce qui se passerait autrement, c'est que les valeurs de allocate
et free
sont recherchées, et nous ne le voulons pas. Dans notre Lisp, nous voulons faire:
(dolist (entry allocation-log)
(case (first entry)
(allocate (plot-allocation (second entry)))
(free (plot-free (second entry)))))
Pour les données indiquées ci-dessus, la séquence suivante d'appels de fonction aurait été:
(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)
Mais Qu'en est-list
?
Eh bien, parfois vous do voulez évaluer les arguments. Supposons que vous ayez une fonction astucieuse manipulant un nombre et une chaîne et renvoyant une liste des choses ... résultantes. Faisons un faux départ:
(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))
Hey! Ce n'est pas ce que nous voulions. Nous voulons sélectivement évaluer certains arguments, et laisser les autres comme des symboles. Essayez # 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)
pas seulement quote
, mais backquote
beaucoup mieux! Incidemment, ce modèle est si commun dans les macros (pour la plupart), qu'il y a une syntaxe spéciale pour ce faire.Le backquote:
(defun mess-with (number string)
`(value-of-number ,(1+ number) something-with-string ,(length string)))
Il est comme l'utilisation quote
, mais avec la possibilité d'évaluer explicitement certains arguments en les faisant précéder par des virgules. Le résultat équivaut à utiliser list
, mais si vous générez du code à partir d'une macro, vous ne voulez souvent évaluer que de petites parties du code retourné, de sorte que la citation arrière convient mieux. Pour les listes plus courtes, list
peut être plus lisible.
Hé, vous avez oublié quote
!
Alors, où cela nous laisse-t-il? Oh, à droite, que fait réellement quote
? Il retourne simplement son argument (s) non évalué! Rappelez-vous ce que j'ai dit au début sur les fonctions régulières? Il s'avère que certains opérateurs/fonctions doivent pas évaluer leurs arguments. Tels que IF - vous ne voudriez pas que la branche else soit évaluée si elle n'a pas été prise, n'est-ce pas? Ce que l'on appelle opérateurs spéciaux, ainsi que des macros, fonctionnent comme ça. Les opérateurs spéciaux sont aussi l '«axiome» du langage - un ensemble minimal de règles - sur lequel vous pouvez implémenter le reste de Lisp en les combinant de différentes manières.
Retour à quote
, si:
Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL
Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL
Comparer à (sur Common Lisp acier-Bank):
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]
Parce qu'il n'y a pas spiffy-symbol
dans le périmètre actuel!
Résumer
quote
, backquote
(par des virgules), et list
sont quelques-uns des outils utilisés pour créer des listes, qui ne sont pas seulement des listes de valeurs, mais comme vous vu peut être utilisé comme léger (pas besoin de définir une structure de données struct
)!
Si vous souhaitez en savoir plus, je recommande le livre Practical Common Lisp de Peter Seibel pour une approche pratique de l'apprentissage de Lisp, si vous êtes déjà dans la programmation en général. Finalement, lors de votre voyage Lisp, vous commencerez à utiliser des paquets aussi. Le The Idiot's Guide to Common Lisp Packages de Ron Garret vous donnera une bonne explication de ceux-ci.
Joyeux hacking!
Comment peut-on l'évaluer alors, par exemple, y at-il une commande 'unquote'? – William
@William Lisps a une fonction pratique appelée 'eval':' (print (eval '(+ 3 4))) '. C'est ce qui rend Lisps si génial: les listes sont du code, et le code est des listes, donc un programme Lisp peut se manipuler lui-même. – darkfeline