Question

Après avoir parcouru les parties principales d'un livre d'introduction à Lisp, je ne comprenais toujours pas ce que faisait la fonction d'opérateur spécial (citation) (ou ') , pourtant, tout cela est sur le code Lisp que j'ai vu.

Qu'est-ce que ça fait?

Était-ce utile?

La solution

Réponse courte Ignorez les règles d'évaluation par défaut et ne pas évaluez l'expression (symbol ou s-exp) en la transmettant à la fonction exactement telle qu'elle est typée.

Réponse longue: la règle d'évaluation par défaut

Lorsqu'une fonction régulière (j'y reviendrai plus tard) est invoquée, tous les arguments qui lui sont transmis sont évalués. Cela signifie que vous pouvez écrire ceci:

(* (+ a 2)
   3)

Qui à son tour évalue (+ a 2) , en évaluant un et 2. La valeur du symbole un est recherchée dans le groupe de liaison de variable en cours, puis remplacé. Disons que a est actuellement lié à la valeur 3:

(let ((a 3))
  (* (+ a 2)
     3))

Nous obtiendrions (+ 3 2) , + est ensuite invoqué les nombres 3 et 2, ce qui donne 5. Notre formulaire original est maintenant (* 5 3) , ce qui donne 15 .

Expliquez citation Déjà!

Très bien. Comme indiqué ci-dessus, tous les arguments d'une fonction sont évalués. Par conséquent, si vous souhaitez transmettre le symbole a et non sa valeur, vous ne souhaitez pas l'évaluer. Les symboles Lisp peuvent doubler leur valeur, ainsi que les marqueurs dans lesquels vous auriez utilisé des chaînes, telles que des clés pour les tables de hachage.

C’est là que quote entre. Indiquez que vous souhaitez tracer les allocations de ressources à partir d’une application Python, mais effectuer plutôt le traçage dans Lisp. Demandez à votre application Python de faire quelque chose comme ça:

print("'(")
while allocating:
    if random.random() > 0.5:
        print(f"(allocate {random.randint(0, 20)})")
    else:
        print(f"(free {random.randint(0, 20)})")
    ...
print(")")

Vous donnez une sortie ressemblant à ceci (légèrement jolie):

'((allocate 3)
  (allocate 7)
  (free 14)
  (allocate 19)
  ...)

Vous souvenez-vous de ce que j'ai dit à propos de quote ("tick"), ce qui empêche la règle par défaut de s'appliquer? Bien. Ce qui arriverait sinon, c’est que les valeurs de allocate et de free sont recherchées, et nous ne le souhaitons pas. Dans notre Lisp, nous souhaitons 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é effectuée:

(plot-allocation 3)
(plot-allocation 7)
(plot-free 14)
(plot-allocation 19)

Mais qu'en est-il de la liste ?

Eh bien, vous voulez parfois évaluer les arguments. Disons que vous avez une fonction astucieuse manipulant un nombre et une chaîne et retournant 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))

Hé! Ce n'est pas ce que nous voulions. Nous voulons évaluer sélectivement certains arguments et laisser les autres sous forme de 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 citation , mais citation arrière

Bien mieux! Incidemment, ce modèle est si commun dans (principalement) les macros, qu'il existe une syntaxe spéciale pour le faire. La citation arrière:

(defun mess-with (number string)
  `(value-of-number ,(1+ number) something-with-string ,(length string)))

C'est comme si vous utilisiez quote , mais avec l'option d'évaluer explicitement certains arguments en les préfixant par une virgule. Le résultat est équivalent à l'utilisation de list , mais si vous générez du code à partir d'une macro, vous ne voulez souvent qu'évaluer de petites parties du code renvoyé. Pour des listes plus courtes, list peut être plus lisible.

Hé, vous avez oublié la citation !

Alors, où cela nous mène-t-il? Oh, d'accord, que fait citation ? Il retourne simplement ses arguments non évalués! Vous souvenez-vous de ce que j'ai dit au début à propos des fonctions régulières? Il s'avère que certains opérateurs / fonctions doivent ne pas évaluer leurs arguments. Tels que IF - vous ne voudriez pas que l’autre branche soit évaluée si elle n’a pas été prise, n’est-ce pas? Les soi-disant opérateurs spéciaux , ainsi que les macros, fonctionnent comme cela. Les opérateurs spéciaux sont également les "axiomes". du langage - 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 , bien que:

Lisp> (quote spiffy-symbol)
SPIFFY-SYMBOL

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above
SPIFFY-SYMBOL

Comparez à (sur le Lisp commun de Steel-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 de symbole spiffy dans la portée actuelle!

Résumé

quote , backquote (avec virgule) et liste sont quelques-uns des outils que vous utilisez pour créer des listes, qui ne sont pas que des listes. de valeurs, mais comme vous pouvez le constater, vous pouvez utiliser des structures de données légères (inutile de définir une structure struct )!

Si vous souhaitez en savoir plus, je vous 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 également à utiliser des packages. Le guide de Idiot sur les paquets Lisp communs de Ron Garret vous en donnera une bonne explication.

Joyeux piratage!

Autres conseils

Il est dit "ne m'évaluez pas". Par exemple, si vous souhaitez utiliser une liste en tant que données, et non en tant que code, vous devez placer une citation devant. Par exemple,

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

D'autres personnes ont admirablement répondu à cette question et Matthias Benkard lance un excellent avertissement.

N'UTILISEZ PAS DE DEVIS POUR CRÉER DES LISTES QUE VOUS MODIFIEREZ PLUS TARD. La spécification permet au compilateur de traiter les listes citées comme des constantes. Souvent, un compilateur optimise les constantes en leur créant une valeur unique 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, elle peut traiter la constante comme une variable globale anonyme.

Cela 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 du code totalement indépendant. Par exemple, vous pouvez comparer une variable à '(1 1) dans une fonction, et dans une fonction complètement différente, commencer une liste avec' (1 1) puis y ajouter des éléments. Lors de l’exécution de ces fonctions, vous constaterez peut-être que la première fonction ne correspond plus, car elle tente maintenant de comparer la variable à '(1 1 2 3 5 8 13), ce que la deuxième fonction a renvoyé. Ces deux fonctions n'ont aucun lien, mais elles ont un effet l'une sur l'autre en raison de l'utilisation de constantes. Même de plus mauvais effets peuvent se produire, comme une itération de liste parfaitement normale, une boucle soudaine et infinie.

Utilisez une citation lorsque vous avez besoin d’une liste constante, telle que pour la comparaison. Utilisez liste lorsque vous modifierez le résultat.

Une réponse à cette question indique que QUOTE & # 8220; crée des structures de données de liste & # 8221 ;. Ce n'est pas tout à fait correct. CITATION est plus fondamental que cela. En fait, QUOTE est un opérateur trivial: son objectif est d'empêcher tout ce qui se passe. En particulier, cela ne crée rien.

Ce que (QUOTE X) dit, c’est fondamentalement: "Ne faites rien, donnez-moi simplement X". X ne doit pas nécessairement être une liste comme dans (DEVIS (A B C)) ou un symbole comme dans (QUOTE FOO). Ce 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 simplement SOME-OBJECT, quel qu’il soit.

Maintenant, la raison pour laquelle (QUOTE (A B C)) semble avoir créé une liste dont les éléments sont A, B et C est qu’une telle liste est vraiment ce qu’elle renvoie; mais au moment où le formulaire QUOTE est évalué, la liste existe généralement déjà depuis un certain temps (en tant que composant du formulaire QUOTE!), créée par le chargeur ou le lecteur avant l'exécution du code.

Une des implications de ce qui a tendance à faire trébucher les débutants assez souvent est qu’il est très déconseillé de modifier une liste renvoyée par un formulaire QUOTE. Les données renvoyées par QUOTE doivent, à toutes fins utiles, être considérées comme faisant partie du code en cours d'exécution et doivent donc être traitées en lecture seule!

La citation empêche l'exécution ou l'évaluation d'un formulaire, mais le transforme en données. En général, vous pouvez exécuter les données en les évaluant ensuite.

quote crée des structures de données de liste. Par exemple, les éléments suivants sont équivalents:

(quote a)
'a

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

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

Vous avez probablement intérêt à vous procurer un livre d'introduction à lisp, tel que Practical Common Lisp (qui est disponible en ligne).

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 passant lors de l'utilisation de listes, de paires et d'atomes qui ne sont pas disponibles dans le langage de programmation C (la plupart des gens commencent à programmer en utilisant la programmation C, nous sommes donc confus) Ceci est un code en langage de programmation Scheme qui est un dialecte 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) transmet abc comme pour la procédure permettant de vérifier si abc est un atome ou non, mais lorsque vous passez (atome? abc), il vérifie la valeur de abc et des passes la valeur à elle. Depuis, nous n’avons fourni aucune valeur

Dans Emacs Lisp:

Que peut-on citer?

Listes et symboles.

Citer un nombre équivaut au nombre lui-même: '5 est identique à 5 .

Que se passe-t-il lorsque vous citez des listes?

Par exemple:

'(un deux) correspond à

(liste 'un' deux) qui correspond à

(liste (interne "un") (interne ("deux"))) .

(intern " one ") crée un symbole nommé "one "". et le stocke dans un emplacement "central". hash-map, donc chaque fois que vous dites 'one , le symbole nommé "un" sera recherché dans cette hash-map centrale.

Mais qu'est-ce qu'un symbole?

Par exemple, dans les langages OO (Java / Javascript / Python), un symbole peut être représenté sous la forme d'un objet doté d'un champ nom , qui est le nom du symbole, comme "un". ; ci-dessus, des données et / ou du code peuvent être associés à cet objet.

Ainsi, un symbole en Python pourrait être implémenté comme suit:

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) des données qui lui sont associées ET (en même temps - pour le même symbole) 2) du code qui lui est 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é à 4 .

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

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

Ainsi, par exemple, en utilisant la classe Symbol définie en Python ci-dessus, ce add ELisp-Symbol pourrait être écrit en Python sous la forme Symbol (" ajouter ", (lambda x, y: x + y), 2) .

Merci beaucoup aux gens de IRC #emacs pour m'avoir expliqué les symboles et les citations.

Quote renvoie la représentation interne de ses arguments. Après avoir exploré beaucoup trop d'explications sur ce que la citation ne fait pas , c'est à ce moment-là que l'ampoule s'est allumée. Si le REPL n'a pas converti les noms de fonction en MAJUSCULES lorsque je les ai cités, cela ne me serait peut-être pas apparu.

Alors. Les fonctions Lisp ordinaires convertissent leurs arguments en représentation interne, évaluent les arguments et appliquent la fonction. Citation convertit ses arguments en une représentation interne, et le renvoie simplement. Techniquement, il est correct de dire que la citation dit: "n'évalue pas", mais lorsque j'essayais de comprendre ce que cela faisait, me dire que ce qu'elle ne faisait pas était frustrant. Mon grille-pain n'évalue pas non plus les fonctions Lisp. mais ce n’est pas ainsi que vous expliquez ce que fait un grille-pain.

Réponse courte à une autre:

quote signifie sans l’évaluer, et la citation arrière est une citation mais laissez la porte arrière .

Une bonne référence:

Le manuel de référence Lisp d’Emacs est très clair

9.3 Citations

La citation de forme spéciale renvoie son unique argument, tel qu’écrit, sans l’évaluer. Cela fournit un moyen d'inclure des symboles constants et des listes, qui ne sont pas des objets auto-évaluables, dans un programme. (Il n'est pas nécessaire de citer des objets auto-évaluateurs tels que des nombres, des chaînes et des vecteurs.)

Forme spéciale: objet quote

This special form returns object, without evaluating it. 

Etant donné que quote est souvent utilisé dans les programmes, Lisp fournit une syntaxe de lecture pratique. Un caractère apostrophe (& # 8216; '& # 8217;) 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 utilisant la citation:

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

(quote foo)
     ⇒ foo

'foo
     ⇒ foo

''foo
     ⇒ (quote foo)

'(quote foo)
     ⇒ (quote foo)

9.4 Backquote

Les constructions Backquote vous permettent de citer une liste, mais d’évaluer sélectivement les éléments de cette liste. Dans le cas le plus simple, il est identique à la citation de formulaire spécial (décrite dans la section précédente; voir Cotation). 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 & # 8216;, & # 8217; à l’arrière de l’argument à indiquer, c’est une valeur qui n’est pas constante. L'évaluateur Lisp d'Emacs évalue l'argument de & # 8216;, & # 8217 ;, et place la valeur dans la structure de liste:

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

Substitution avec & # 8216;, & # 8217; est autorisé à des niveaux plus profonds de la structure de liste également. Par exemple:

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

Vous pouvez également associer une valeur évaluée à la liste obtenue à l'aide du marqueur spécial & # 8216;, @ & # 8217 ;. Les éléments de la liste épissée deviennent des éléments du même niveau que les autres éléments de la liste résultante. Le code équivalent sans utiliser & # 8216; `& # 8217; 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)
Code is data and data is code.  There is no clear distinction between them.

C’est une déclaration classique que tout programmeur Lisp connaît.

Lorsque vous citez un code, ce code sera une donnée.

1 ]=> '(+ 2 3 4)
;Value: (+ 2 3 4)

1 ]=> (+ 2 3 4)
;Value: 9

Lorsque vous citez un code, le résultat sera des données représentant ce code. Ainsi, lorsque vous souhaitez utiliser des données représentant un programme, vous citez ce programme. Ceci est également valable pour les expressions atomiques, pas seulement pour les listes:

1 ]=> 'code
;Value: code

1 ]=> '10
;Value: 10

1 ]=> '"ok"
;Value: "ok"

1 ]=> code
;Unbound variable: code

Supposons que vous souhaitiez créer un langage de programmation intégré à lisp - vous travaillerez avec des programmes cités de manière schématique (comme '(+ 2 3) ) et interprétés comme du code dans le fichier. langue que vous créez, en donnant aux programmes une interprétation sémantique. Dans ce cas, vous devez utiliser quote pour conserver les données, sinon elles seront évaluées dans un langage externe.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top