2008-09-25 4 views
89

Après avoir traversé les parties majeures d'un livre Lisp d'introduction, je ne comprenais toujours pas ce que fait la fonction (quote) (ou l'équivalent ') de l'opérateur spécial, pourtant cela a été partout le code Lisp que j'ai vu.Quand utiliser '(ou quote) dans Lisp?

Que fait-il?

Répondre

148

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!

48

Il est écrit "ne m'évaluez pas". Par exemple, si vous souhaitez utiliser une liste comme données, et non comme code, vous devez placer une citation devant celle-ci. Par exemple,

(print '(+ 3 4)) impressions "(3 + 4)", tandis que (print (+ 3 4)) imprime "7"

+0

Comment peut-on l'évaluer alors, par exemple, y at-il une commande 'unquote'? – William

+1

@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

9

La citation empêche l'exécution ou à l'évaluation d'une forme, en le transformant en données à la place. En général, vous pouvez exécuter les données en les évaluant.

citation crée des structures de données de la liste, par exemple, les suivantes sont équivalentes:

(quote a) 
'a 

Il peut également être utilisé pour créer des listes (ou des arbres):

(quote (1 2 3)) 
'(1 2 3) 

Vous êtes probablement mieux off obtenir un livre d'introduction sur Lisp, comme Practical Common Lisp (qui est disponible à lire en ligne).

11

Une réponse à cette question indique que QUOTE "crée des structures de données de liste". Ce n'est pas tout à fait correct. QUOTE est plus fondamental que cela. En fait, QUOTE est un opérateur trivial: Son but est de empêcher rien de se produire du tout. En particulier, il ne crée rien. Ce que dit (QUOTE X) est fondamentalement "ne fais rien, donne moi X." X n'a ​​pas besoin d'être une liste comme dans (QUOTE (A B C)) ou un symbole comme dans (QUOTE FOO). Cela peut être n'importe quel objet. En effet, le résultat de l'évaluation de la liste produite par (LIST 'QUOTE SOME-OBJECT) retournera toujours SOME-OBJECT, quel qu'il soit.

Maintenant, la raison pour laquelle (QUOTE (A B C)) semble créer une liste dont les éléments sont A, B et C est qu'une telle liste est vraiment ce qu'elle retourne; mais au moment où la forme QUOTE est évaluée, la liste existe généralement déjà depuis un certain temps (en tant que composant du formulaire QUOTE!), créée soit par le chargeur, soit par le lecteur avant l'exécution du code. Une implication de ce qui tend à trébucher assez souvent les débutants est qu'il est très imprudent de modifier une liste retournée par un formulaire QUOTE. Les données retournées par QUOTE sont, à toutes fins utiles, à considérer comme faisant partie du code en cours d'exécution et doivent donc être traitées comme étant en lecture seule!

13

D'autres personnes ont répondu admirablement à cette question, et Matthias Benkard évoque un excellent avertissement. NE PAS UTILISER CITER POUR CRÉER DES LISTES QUE VOUS DEVEZ MODIFIER ULTÉRIEUREMENT. La spécification permet au compilateur de traiter les listes entre guillemets comme des constantes. Souvent, un compilateur optimise les constantes en leur créant une seule valeur en mémoire, puis en référençant cette valeur unique à partir de tous les emplacements où la constante apparaît. En d'autres termes, il peut traiter la constante comme une variable globale anonyme.

Ceci peut causer des problèmes évidents. Si vous modifiez une constante, cela peut très bien modifier d'autres utilisations de la même constante dans un code complètement indépendant. Par exemple, vous pouvez comparer une variable à '(1 1) dans certaines fonctions, et dans une fonction complètement différente, démarrez une liste avec' (1 1), puis ajoutez-y plus de choses. Lors de l'exécution de ces fonctions, vous pouvez constater que la première fonction ne correspond plus correctement, car elle essaie maintenant de comparer la variable à '(1 1 2 3 5 8 13), ce qui est retourné par la seconde fonction.Ces deux fonctions sont complètement indépendantes, mais elles ont un effet l'une sur l'autre en raison de l'utilisation de constantes. Des effets encore plus fous peuvent se produire, comme une itération de liste parfaitement normale et soudainement en boucle infinie.

Utilisez un guillemet lorsque vous avez besoin d'une liste de constantes, par exemple pour la comparaison. Utilisez la liste lorsque vous modifierez le résultat.

+0

Il semble donc que vous devriez utiliser '(list (+ 1 2))' la plupart du temps. Si oui, comment empêchez-vous l'évaluation de '(+ 1 2)' dans un tel exemple? Y a-t-il une commande 'unquote'? – William

+0

Voulez-vous l'équivalent de ''((3))', ou l'équivalent de '' ((+ 1 2))'? Si ce dernier, vous devez utiliser plus 'list':' (list (list '+ 1 2)) '. Ou si vous voulez l'équivalent de ''(+ 1 2)', juste '(list' + 1 2)'. Et rappelez-vous, si vous ne modifiez pas la liste, n'hésitez pas à utiliser la citation: rien à redire à ''(+ 1 2)' si vous comparez simplement avec ou contre quelque chose. – Xanthir

+0

Est-ce que cela vous dérange de faire référence aux endroits où les listes entre guillemets sont censées être traitées comme des constantes? – William

2

Lorsque nous voulons passer un argument lui-même au lieu de passer la valeur de l'argument, nous utilisons quote. Il est principalement lié à la procédure qui passe lors de l'utilisation de listes, paires et atomes qui ne sont pas disponibles en langage de programmation C (la plupart des gens commencent à programmer en utilisant la programmation C, donc nous sommes confus) Ceci est un code dans le langage de programmation Scheme de Lisp et je suppose que vous pouvez comprendre ce code.

(define atom?    ; defining a procedure atom? 
    (lambda (x)    ; which as one argument x 
(and (not (null? x)) (not(pair? x))))) ; checks if the argument is atom or not 
(atom? '(a b c)) ; since it is a list it is false #f 

La dernière ligne (atome? Abc) passe abc comme il est à la procédure pour vérifier si abc est un atome ou non, mais quand vous passez (atome? Abc), il vérifie la valeur de abc et lui passe la valeur. Depuis, nous ne lui avons fourni aucune valeur

0

La citation renvoie la représentation interne de ses arguments. Après avoir labouré à travers trop d'explications de ce que cite ne fait pas, c'est alors que l'ampoule a continué. Si le REPL n'a pas converti les noms de fonction en MAJUSCULES quand je les ai cités, cela peut ne pas m'être apparu.

Donc. Les fonctions Lisp ordinaires convertissent leurs arguments en une représentation interne, évaluent les arguments et appliquent la fonction. Quote convertit ses arguments en une représentation interne, et renvoie juste cela. Techniquement, il est correct de dire que la citation dit «n'évaluent pas», mais quand j'essayais de comprendre ce qu'elle faisait, me dire ce qu'elle ne faisait pas était frustrant. Mon grille-pain n'évalue pas non plus les fonctions Lisp; mais ce n'est pas comme ça que vous expliquez ce que fait un grille-pain.

0

Anoter réponse courte:

quote signifie sans l'évaluer, et backquote est citation, mais laisser portes arrière.

Une bonne référenceVoitures:

Emacs Lisp Manuel de référence, il est très clair

9.3 Citant

La citation de forme spéciale renvoie son seul argument, tel qu'il est écrit, sans l'évaluer. Cela permet d'inclure des symboles constants et des listes, qui ne sont pas des objets à auto-évaluation, dans un programme. (Il ne faut pas citer des objets d'auto-évaluation, tels que des nombres, des chaînes et des vecteurs.)

Formulaire spécial: citation objet

This special form returns object, without evaluating it. 

Comme citation est utilisé si souvent dans les programmes, Lisp fournit une pratique lire la syntaxe pour cela. Un caractère apostrophe ('' ') suivi d'un objet Lisp (en syntaxe de lecture) se développe en une liste dont le premier élément est quote, et dont le second élément est l'objet. Ainsi, la syntaxe de lecture 'x est une abréviation de (quote x).

Voici quelques exemples d'expressions qui utilisent citation:

(quote (+ 1 2)) 
    ⇒ (+ 1 2) 

(quote foo) 
    ⇒ foo 

'foo 
    ⇒ foo 

''foo 
    ⇒ (quote foo) 

'(quote foo) 
    ⇒ (quote foo) 

9.4 BACKQUOTE

constructions BACKQUOTE vous permettent de citer une liste, mais évaluer de manière sélective des éléments de cette liste. Dans le cas le plus simple, il est identique au devis de formulaire spécial (décrit dans la section précédente, voir Citations). Par exemple, ces deux formes donnent des résultats identiques:

`(a list of (+ 2 3) elements) 
    ⇒ (a list of (+ 2 3) elements) 

'(a list of (+ 2 3) elements) 
    ⇒ (a list of (+ 2 3) elements) 

Le marqueur spécial « » à l'intérieur de l'argument à backquote indique une valeur non constante. L'évaluateur Lisp évalue l'argument de « » et met la valeur dans la structure de la liste:

`(a list of ,(+ 2 3) elements) 
    ⇒ (a list of 5 elements) 

Remplacement avec « » est autorisé à des niveaux plus profonds de la structure de la liste aussi. Par exemple:

`(1 2 (3 ,(+ 4 5))) 
    ⇒ (1 2 (3 9)) 

Vous pouvez également raccorder une valeur évaluée dans la liste obtenue, en utilisant le marqueur spécial «@ ». Les éléments de la liste épissée deviennent des éléments au même niveau que les autres éléments de la liste résultante. Le code équivalent sans utiliser '`' est souvent illisible. Voici quelques exemples:

(setq some-list '(2 3)) 
    ⇒ (2 3) 

(cons 1 (append some-list '(4) some-list)) 
    ⇒ (1 2 3 4 2 3) 

`(1 ,@some-list 4 ,@some-list) 
    ⇒ (1 2 3 4 2 3) 
1

Emacs Lisp:

Que peut-être cotées en bourse?

Listes et symboles.

La citation d'un nombre évalue le nombre lui-même: '5 est la même que 5. Que se passe-t-il lorsque vous citez des listes?

Par exemple:

'(one two) est évaluée à

(list 'one 'two) qui évalue à

(list (intern "one") (intern ("two"))).

(intern "one") crée un symbole nommé « un » et le stocke dans une carte de hachage « central », donc chaque fois que vous dites 'one alors le symbole nommé "one" sera recherché dans cette centrale de hachage carte.

Mais qu'est-ce qu'un symbole?

Par exemple, dans OO-langues (Java/Javascript/Python) un symbole peut être représenté comme un objet qui a un dessus du champ name, qui est le nom du symbole comme "one", et les données et/ou le code peuvent être associé à cet objet.

donc un symbole en Python pourrait être mis en œuvre comme:

class Symbol: 
    def __init__(self,name,code,value): 
     self.name=name 
     self.code=code 
     self.value=value 

Dans Emacs Lisp par exemple un symbole peut avoir 1) données associées et (en même temps - pour le même symbole) 2) code associé - en fonction du contexte, les données ou le code sont appelés.

Par exemple, dans Elisp:

(progn 
    (fset 'add '+) 
    (set 'add 2) 
    (add add add) 
) 

est évaluée à 4.

Parce que (add add add) est évaluée comme:

(add add add) 
(+ add add) 
(+ 2 add) 
(+ 2 2) 
4 

Ainsi, par exemple, en utilisant l'on a défini en Python ci-dessus classe Symbol, ce add Elisp-Symbol pourrait être écrit en Python comme Symbol("add",(lambda x,y: x+y),2).

Un grand merci pour les gens sur IRC#emacs pour m'expliquer des symboles et des citations.

Questions connexes