Символ, який знаходиться у нефункціональному положенні, трактується як назва змінної. Перебуває (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")
. Взагалі, Елісп не надто послідовний щодо аргументованих аргументів проти не цитованих, але будь-яка функція (не макрос), якій потрібно взаємодіяти зі змінною замість значення, буде брати аргумент, який цитується (setq
є головним винятком).