Символ, который находится в нефункциональном положении, обрабатывается как имя переменной. In (function variable)
function
находится в функции-положении (после открывающей скобки) и variable
не находится. Если явно не заключенные в кавычки переменные заменены их значениями.
Если бы вы написали (boundp my-variable)
, это означало бы «это символ, который хранится в значении переменной, my-variable
связанной как переменная», а не «это символ, my-variable
связанный как переменная.
Так почему же bound-and-truep
ведет себя по-другому?
Это макрос, и нормальные (функциональные) правила оценки здесь не применяются, макросы могут сами решать, когда и когда их аргументы оцениваются. Что на самом деле делают макросы, так это как-то преобразовывают аргументы и возвращают результат в виде списка, который затем оценивается. Преобразование и окончательная оценка происходят в разное время, называемое временем макроразложения и временем оценки.
Вот как 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))
При этом используются макросы чтения, которые отличаются от макросов lisp (подробнее об этом ниже). Чтобы не усложнять это далее, давайте не будем использовать какие-либо макросы чтения:
(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))
Если ты пишешь
(bound-and-true-p my-variable)
который сначала "переводится" на
(and (boundp 'my-variable) my-variable)
и затем это вычисляется, возвращая, nil
если my-variable
это не так boundp
или иначе значение my-variable
(которое, конечно, также может быть nil
).
Вы могли заметить, что расширение не было
(and (boundp (quote my-variable)) my-variable)
как мы могли ожидать. quote
это специальная форма, а не макрос или функция. Как и макросы, специальные формы могут делать что угодно со своими аргументами. Эта особая специальная форма просто возвращает свой аргумент, здесь символ, вместо значения переменной символа. Это единственная цель этой специальной формы: предотвращение оценки! Макросы не могут сделать это самостоятельно, они должны использовать quote
это.
Так в чем дело '
? Это макрос для чтения , который, как упоминалось выше, не совпадает с макросом LISP . В то время как макросы используются для преобразования кода / данных, макросы чтения используются ранее при чтении текста, чтобы преобразовать этот текст в код / данные.
'something
это короткая форма для
(quote something)
`
в настоящем определении bound-and-true-p
также используется макрос для чтения. Если он заключает в кавычки символ как в `symbol
нем, это эквивалентно 'symbol
, но когда используется для цитирования списка, так как `(foo bar ,baz)
он ведет себя по-разному в тех формах, с которыми ставится префикс ,
, оцениваются.
`(constant ,variable)
эквивалентно
(list (quote constant) variable))
Это должно ответить на вопрос, почему символы без кавычек иногда оцениваются (заменяются их значениями), а иногда нет; Макросы можно использовать quote
для предотвращения оценки символа.
Но почему bound-and-true-p
макроса пока boundp
нет? Мы должны быть в состоянии определить, связаны ли произвольные символы, которые не известны до времени выполнения, как символы. Это было бы невозможно, если boundp
аргумент был автоматически указан.
bound-and-true-p
используется, чтобы определить, определена ли известная переменная и, если да, использовать ее значение. Это полезно, если библиотека имеет необязательную зависимость от сторонней библиотеки, как в:
(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-p
может быть определена как функция и требует, чтобы аргумент был заключен в кавычки, но потому что он предназначен для случаев, когда вы заранее знаете, какая переменная, которую вы заботитесь о макросе, использовалась, чтобы избавить вас от необходимости вводить '
.
setq
означаетset quoted
, и изначально был макрос, который расширился в(set 'some-variable "less")
. В целом, Elisp не очень согласован в отношении аргументов, заключенных в кавычки, а не в кавычки, но любая функция (не макрос), которая должна взаимодействовать с переменной, а не со значением, получит свой аргумент в кавычках (setq
что является основным исключением).