Comment savoir quand ou quand ne pas utiliser le guillemet simple avant les noms de variables?

31

J'ai ce qui suit:

(setq some-variable "less")

Je ne comprends pas pourquoi je dois utiliser la citation unique avec boundpmais pas avec bound-and-true-p.

Exemple 1:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))

Résultat:

"une variable est moins"

Exemple 2a:

(when (bound-and-true-p some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Résultat:

"une variable est moins"

Exemple 2b:

(when (bound-and-true-p 'some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Résultat:

et: Argument de type incorrect: symbolp, (citez une variable)

Kaushal Modi
la source
5
Il convient de mentionner que cela setqsignifie set quotedet était à l'origine une macro qui s'est développée (set 'some-variable "less"). En général, Elisp n'est pas terriblement cohérent à propos des arguments entre guillemets et sans guillemets, mais toute fonction (pas une macro) qui doit interagir avec une variable au lieu d'une valeur prendra son argument entre guillemets ( setqétant une exception majeure).
shosti
2
FWIW, bound-and-true-pest une macro stupide. Ou plutôt, son nom est stupide. 99,99% du temps lorsque vous voulez le faire, (and (boundp 'FOO) FOO)vous utilisez la valeur deFOO . Vous ne le faites pas simplement pour obtenir une valeur de vérité. (1) La macro n'est pas nécessaire - le code qu'elle remplace est trivial et petit. (2) Le nom est trompeur - il s'agit de la valeur de la variable, pas seulement de tester si la valeur de la variable l'est ou non nil.
Drew

Réponses:

24

Réponse courte

Si vous essayez d'utiliser la variable elle-même, utilisez 'some-variable. Si vous essayez d'utiliser la valeur stockée dans la variable, utilisez some-variable.

  • boundp utilise le symbole pour regarder tout ce qui peut être lié, y compris les fonctions. Il se soucie seulement de savoir s'il existe un symbole qui correspond, pas quelle est la valeur.
  • bound-and-truep utilise var et renvoie la valeur. Dans ce cas, vous devez fournir la valeur du symbole à la fonction. Si aucun symbole var n'est lié, ou si la valeur est nulle, il retournera nil.

Explication

Pour la définition du manuel, veuillez consulter le manuel .

'et les (quote ...)deux remplissent le même rôle dans emacs-lisp.

Le but est de transmettre la forme non évaluée au milieu environnant plutôt que de l'évaluer.

Dans votre exemple, supposons que nous avions les éléments suivants plus haut

(setq some-variable "less") ;; Rather than just 't for clarity

Ensuite, l'évaluation se déroule comme suit:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))
;; ==> (boundp 'some-variable) ; 't
;; ==> some-variable is "less"

Alors que sans devis:

(when (boundp some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))
;; ==> (boundp "less") ; "less" is not a variable. -> Error

Lisp évalue les formulaires lorsqu'ils sont atteints, en citant le formulaire que vous empêchez l'évaluation afin que la variable réelle (ou la liste ou le nom de la fonction) soit transmise.

Jonathan Leech-Pepin
la source
Merci! Votre réponse m'a fait sauter dans les sources des deux et m'a aidé à trouver la solution. J'ai également mis à jour ma question avec des exemples clairs.
Kaushal Modi du
6
Je suis heureux que cela ait aidé l'opération, mais cela ne répond pas réellement à la question (d'une manière utile pour d'autres personnes ayant la même question). Vous expliquez seulement que les symboles doivent être cités, sinon ils sont évalués. Vous n'expliquez pas pourquoi ce n'est pas le cas bound-and-truepet la question était de savoir pourquoi dois-je citer lors de l'utilisation, boundpmais pas lors de l'utilisation bound-and-truep.
tarsius
@tarsius J'inclus en fait la distinction entre boundpexiger un symbole (non évalué) et bound-and-truepavoir besoin de la valeur de la variable dans les puces (édité après la réponse initiale)
Jonathan Leech-Pepin
Je pense qu'il est essentiel de mentionner pourquoi il en est ainsi (les macros peuvent choisir de ne pas évaluer) au lieu de simplement mentionner que la doc-string le dit. Je pense que c'est une très bonne question et que le bornage par rapport au borné-et-vrai-p n'est qu'un exemple. Ce que la question se résume vraiment, c'est le désir d'en apprendre davantage sur les règles d'évaluation.
tarsius
@tarsius Les règles d'évaluation ne sont-elles pas expliquées par cette réponse? Au moins celles de base impliquant uniquement la citation ... Votre réponse est certainement plus complète, mais elle va bien au-delà du sujet, n'est-ce pas?
T. Verron
17

Un symbole qui est en position non fonctionnelle est traité comme le nom d'une variable. In (function variable) functionest en position de fonction (après la parenthèse ouvrante) et variablene l'est pas. Sauf si les variables explicitement citées sont remplacées par leurs valeurs.

Si vous deviez écrire (boundp my-variable)cela signifierait "est le symbole qui est stocké dans la valeur de la variable my-variableliée en tant que variable" et non "est le symbole my-variablelié en tant que variable.

Alors pourquoi bound-and-truepse comporte-t-il différemment?

Il s'agit d'une macro et les règles d'évaluation normales (fonction) ne s'appliquent pas ici, les macros sont libres de décider si et quand leurs arguments sont évalués. Ce que les macros font réellement, c'est d'une manière ou d'une autre de transformer les arguments et de renvoyer le résultat sous forme de liste, qui est ensuite évaluée. La transformation et l'évaluation finale se produisent à différents moments, appelés temps de macro-expansion et temps d'évaluation.

Voici à quoi bound-and-true-pressemble la définition de :

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

Cela utilise des macros de lecteur qui sont différentes des macros lisp (plus d'informations ci-dessous). Pour ne pas compliquer cela, nous ne devons pas utiliser de macros de lecture:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  (list 'and (list 'boundp (list 'quote var)) var))

Si vous écrivez

(bound-and-true-p my-variable)

qui est d'abord "traduit" en

(and (boundp 'my-variable) my-variable)

et ensuite cela est évalué en retournant nilif my-variablen'est pas boundpou bien la valeur de my-variable(qui bien sûr peut aussi être nil).


Vous avez peut-être remarqué que l'extension n'était pas

(and (boundp (quote my-variable)) my-variable)

comme on aurait pu s'y attendre. quoteest une forme spéciale, pas une macro ou une fonction. Comme les macros, les formulaires spéciaux peuvent faire n'importe quoi avec leurs arguments. Cette forme spéciale particulière renvoie simplement son argument, ici un symbole, au lieu de la valeur variable du symbole. C'est en fait le seul but de ce formulaire spécial: empêcher l'évaluation! Les macros ne peuvent pas le faire par elles-mêmes, elles doivent les utiliser quotepour le faire.

Alors quoi de neuf '? Il s'agit d'une macro de lecture qui, comme mentionné ci-dessus, n'est pas la même chose qu'une macro lisp . Alors que les macros sont utilisées pour transformer le code / les données, les macros du lecteur sont utilisées plus tôt lors de la lecture du texte afin de transformer ce texte en code / données.

'something

est une forme abrégée pour

(quote something)

`utilisé dans la définition réelle de bound-and-true-pest également une macro de lecture. S'il cite un symbole comme dans, `symbolil est équivalent à 'symbol, mais quand est utilisé pour citer une liste comme dans, `(foo bar ,baz)il se comporte différemment dans la mesure où les formulaires préfixés ,sont évalués.

`(constant ,variable)

est équivalent à

(list (quote constant) variable))

Cela devrait répondre à la question de savoir pourquoi les symboles non cités sont parfois évalués (remplacés par leurs valeurs) et parfois non; les macros peuvent être utilisées quotepour empêcher l'évaluation d'un symbole.

Mais pourquoi bound-and-true-pune macro boundpne l'est-elle pas? Nous devons être en mesure de déterminer si des symboles arbitraires, qui ne sont pas connus avant l'exécution, sont liés en tant que symboles. Cela ne serait pas possible si l' boundpargument était automatiquement cité.

bound-and-true-pest utilisé pour déterminer si une variable connue est définie et si c'est le cas, utilisez sa valeur. Ceci est utile si une bibliothèque a une dépendance facultative sur une bibliothèque tierce comme dans:

(defun foo-get-value ()
  (or (bound-and-true-p bar-value)
      ;; we have to calculate the value ourselves
      (our own inefficient or otherwise undesirable variant)))

bound-and-true-ppourrait être défini comme une fonction et nécessiter la citation de l'argument, mais parce qu'il est destiné aux cas où vous savez à l'avance quelle variable vous vous souciez d'une macro a été utilisée pour vous éviter d'avoir à taper le '.

tarse
la source
Étonnamment bien répondu.
Charles Ritchie
2

À partir du code source de boundp:

DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
      doc: /* Return t if SYMBOL's value is not void.
Note that if `lexical-binding' is in effect, this refers to the
global value outside of any lexical scope.  */)

boundpattend a symbolcomme entrée. 'some-variableest un symbole de la variable some-variable.

À partir du code source de bound-and-true-p:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

bound-and-true-pattend a variablecomme entrée.

À l'intérieur de la bound-and-true-pmacro, il obtient le symbole en faisant (quote ,var). Donc, si l'entrée est some-variable, se (quote ,var)traduira par 'some-variable.

Mais quand je donne l'entrée 'some-variableà bound-and-true-p, j'obtiens l'erreur: and: Wrong type argument: symbolp, (quote some-variable)parce que la macro n'attend PAS de symbole ( 'some-variable) à l'entrée.

Kaushal Modi
la source
Juste un avertissement. ''symbol a du sens. Ça veut dire (quote (quote symbol)). La raison pour laquelle vous obtenez une erreur est que ce n'est pas un argument valide pour boundp.
Malabarba
@Malabarba Merci. J'ai fait la correction.
Kaushal Modi