Код завершается с: (wrong-type-argument symbolp (if (boundp (quote a)) (quote a) (quote dummy)))
, указывая на то, что специальная форма let
не оценивает этот аргумент (хотя этот список будет вычисляться как символ, сам список не является символом).
Вот простой, но некорректный альтернативный подход, который создает локальную привязку для a
независимо, но затем связывает ее в этой локальной области, если она была изначально не связана.
(let ((a (if (boundp 'a) t nil)))
(or a (makunbound 'a))
;; do things
)
Недостаток в том, что если a
изначально не был связан, вы бы хотели присвоить a
в этой локальной области, чтобы пережить локальную область, и это не будет с этим подходом.
Сначала я думалвам нужно полностью отказаться от let
, чтобы обойти эту проблему, и просто использовать что-то вроде этого:
(when (boundp 'a)
(setq a-backup a
a t))
;; do things
(when (boundp 'a-backup)
(setq a a-backup)
(makunbound 'a-backup))
Тогда я понял, что, как и во многих других случаях, ответом являются макросы:
(defmacro let-if-bound (var value &rest body)
"Bind variable VAR to VALUE only if VAR is already bound."
(declare (indent 2))
`(if (boundp ',var)
(let ((,var ,value))
,@body)
(progn ,@body)))
(let-if-bound a t
;; do things
)
(*) «Специальная форма» - это примитивная функция, специально помеченная так, что ее аргументы не все оцениваются.Большинство специальных форм определяют управляющие структуры или выполняют привязки переменных - то, что функции не могут делать.
Каждая специальная форма имеет свои собственные правила, для которых оцениваются аргументы и которые используются без оценки.Оценка конкретного аргумента может зависеть от результатов оценки других аргументов.