Як знати, коли або коли не використовувати єдину цитату перед назвами змінних?


31

У мене є наступне:

(setq some-variable "less")

Мене бентежить, чому мені доводиться використовувати одну цитату, boundpа не з якою bound-and-true-p.

Приклад 1:

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

Результат:

"деяка змінна менше"

Приклад 2a:

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

Результат:

"деяка змінна менше"

Приклад 2b:

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

Результат:

і: Неправильний аргумент типу: symbolp, (цитуйте деяку змінну)


5
Варто згадати, що setqозначає set quoted, і спочатку це був макрос, який розширився в (set 'some-variable "less"). Взагалі, Елісп не надто послідовний щодо аргументованих аргументів проти не цитованих, але будь-яка функція (не макрос), якій потрібно взаємодіяти зі змінною замість значення, буде брати аргумент, який цитується ( setqє головним винятком).
шості

2
FWIW, bound-and-true-pце дурний макрос. А точніше, його назва дурна. 99,99% часу, коли ви хочете це зробити, (and (boundp 'FOO) FOO)ви робите це, щоб використовувати значенняFOO . Ви не робите це лише для того, щоб отримати значення істини. (1) Макрос не потрібен - код, який він замінює, є тривіальним і малим. (2) Назва вводить в оману - мова йде про значення змінної, а не лише про те, чи є значення змінної чи ні nil.
Дрю

Відповіді:


24

Коротка відповідь

Якщо ви намагаєтеся використовувати саму змінну, тоді використовуйте 'some-variable. Якщо ви намагаєтесь використовувати значення, збережене у змінній, використовуйте some-variable.

  • limitp використовує символ, тому він буде розглядати все, що може бути пов'язано, включаючи функції. Дбає лише те, чи є символ, який відповідає, а не те, яке значення.
  • прив’язаний і truep використовує var і повертає значення. У цьому випадку потрібно надати значення символу функції. Якщо жоден символ var не зв'язаний, або значення є нульовим, воно поверне нуль.

Пояснення

Для визначення вручну див . Посібник .

'і (quote ...)обидва виконують однакову мету в emacs-lisp.

Мета цього - передати неоцінену форму навколишньому середовищу, а не оцінювати її.

У вашому прикладі припустімо, що ми мали наступне вище

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

Потім оцінка йде наступним чином:

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

Тоді як без цитати:

(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

Лісп оцінює форми по мірі їх досягнення, цитуючи форму, яку ви запобігаєте оцінці, щоб передати фактичну змінну (або список, або ім'я функції).


Спасибі! Ваша відповідь змусила мене стрибнути до джерел обох і допомогла мені знайти рішення. Я також оновив своє запитання чіткими прикладами.
Каушал Моді

6
Я радий, що це допомогло операторам, але насправді це не дає відповіді на питання (таким чином, корисним для інших людей, які мають те саме питання). Ви лише пояснюєте, що символи повинні бути котировані, інакше вони оцінюються. Ви не пояснюєте, чому це не так, bound-and-truepі питання полягало в тому, чому я маю цитувати при використанні, boundpа не при використанні bound-and-truep.
Тарсій

@tarsius Я фактично включаю різницю між тим, що boundpвимагати символ (неоціненний) та bound-and-truepпотребувати значення змінної у точках кулі (відредаговано після початкової відповіді)
Джонатан Ліч-Пепін

Я думаю, що важливо згадати, чому це так (макроси можуть вирішити не оцінювати), а не просто згадати, що док-рядок так говорить. Я думаю, що це дуже гарне запитання, і це обмеження порівняно з обмеженим і вірним-р - лише приклад. Питання насправді зводиться до бажання дізнатися про правила оцінювання.
Тарсій

@tarsius Чи не пояснено цією відповіддю правила оцінки? Принаймні базові, що стосуються лише цитати ... Ваша відповідь, безумовно, більш повна, але це виходить далеко за межі теми, чи не так?
Т. Веррон

17

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


Дивовижно добре відповів.
Чарльз Річі

2

Із вихідного коду 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.  */)

boundpочікує, що symbolяк вхід. 'some-variableє символом змінної some-variable.

Із вихідного коду 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-pочікує, що variableяк вхід.

Всередині bound-and-true-pмакросу він отримує символ, виконуючи його (quote ,var). Отже, якщо вхід є some-variable, (quote ,var)призведе до 'some-variable.

Але коли я даю вхід 'some-variableна bound-and-true-p, я отримую помилку: and: Wrong type argument: symbolp, (quote some-variable)тому що макрос не очікує символ ( 'some-variable) на вході.


Просто голова вгору. ''symbol має сенс Це означає (quote (quote symbol)). Причина, за якою ви отримуєте помилку, полягає в тому, що це не вагомий аргумент boundp.
Малабарба

@Malabarba Дякую Я вніс виправлення.
Каушал Моді
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.