symbol-value と boundp はlexical な binding を無視する

(let ((x 'foo))
  (symbol-value 'x))
=> 変数が定義されていません: x

(let ((x 'foo))
  (boundp 'x))
=> nil

なんで・・・

Notes:
The function bound determines only whether a symbol has a value in the global environment; any lexical bindings are ignored.

関数 boundp*1 はグローバル環境でシンボルに値が設定されているかのみを調べます。レキシカルな束縛は無視されます。

CLHS: Function BOUNDP

くっそう、めんどいなぁ。

;; lexical な bindings を取得してみる
(let ((a 'foo) (b 'bar))
  (let ((foo 'spam) (bar 'egg))
    (si:closure-variable (lambda nil))))
=> ((bar . egg) (foo . spam) (b . bar) (a . foo))

;; boundp の代わり ~1
(let ((x 'foo))
  (assoc 'x (si:closure-variable (lambda nil))))
=> (x . foo)

;; boundp の代わり ~2
(let ((x 'foo))
  (handler-case (or x t)
    (unbound-variable (c) nil)))
=> foo

色々考えたけど関数では無理っぽいのでマクロ。

(defmacro lexically-bound-p (symbol)
  `(handler-case (or ,symbol t)
     (unbound-variable (c) nil)))
=> lexically-bound-p

(let ((a 'foo))
  (values (lexically-bound-p a)
          (lexically-bound-p b)))
=> foo
=> nil

*1:"bound" ってたぶん typo だよね