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 '.
setqsignifieset 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).