Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Common Lisp: check if lexical variable exists?

How do I detect if a lexical variable is bound in a scope? I basically want boundp for lexical variables.

Concretely, say I have:

(defvar *dynamic* 1)
(defconstant +constant+ 2)

(let ((lexical 3))
  (when (boundp '*dynamic*)  ; t
    (print "*dynamic* bound."))
  (when (boundp '+constant+) ; t
    (print "+constant+ bound."))
  (when (boundp 'lexical)    ; nil
    (print "lexical bound.")))

So boundp correctly checks for dynamic variables (and constants), and as the hyperspec says, doesn't cover lexical bindings.

But I can't find any equivalent of boundp for lexical bindings. So how do I check them then? (Implementation-specific code for say SBCL is fine if there isn't anything portable.)

like image 987
freya Avatar asked Jun 05 '16 15:06

freya


2 Answers

There is nothing like that in ANSI Common Lisp. There is no access to a lexical environment.

You only can check it this way:

CL-USER 8 > (let ((lexical 3))
              (when (ignore-errors lexical) 
                (print "lexical bound."))
              (values))

"lexical bound." 

CL-USER 9 > (let ((lexical 3))
              (when (ignore-errors lexxxical) 
                (print "lexical bound."))
              (values))
<nothing>

There is no way to take a name and see if it is lexically bound at all. There is an extension to CL, where the function variable-information would give some information, but even in this case it would probably not work:

* (require "sb-cltl2")

("SB-CLTL2")
* (apropos "variable-information")

VARIABLE-INFORMATION
SB-CLTL2:VARIABLE-INFORMATION (fbound)
* (let ((lexical 3))
     (sb-cltl2:variable-information 'lexical))
; in: LET ((LEXICAL 3))
;     (LET ((LEXICAL 3))
;       (SB-CLTL2:VARIABLE-INFORMATION 'LEXICAL))
; 
; caught STYLE-WARNING:
;   The variable LEXICAL is defined but never used.
; 
; compilation unit finished
;   caught 1 STYLE-WARNING condition

NIL
NIL
NIL
like image 118
Rainer Joswig Avatar answered Oct 14 '22 22:10

Rainer Joswig


for cltl2:variable-information to work, it should be done in macro expansion time.

(ql:quickload :introspect-environment)
(use-package :introspect-environment) ;; also exports cltl2 functions.

(defmacro in-compile-time ((environment) &body body &environment env)
  (check-type environment symbol)
  (eval `(let ((,environment ,env)) (progn ,@body)))
  nil) ; does not affect the expansion

(defun fn ()
  (let ((lexical 2))
    (in-compile-time (env)
      (print (introspect-environment:variable-information 'lexical env))
      (print (introspect-environment:variable-information 'lexxxxical env)))))
; compiling (DEFUN FN ...)
:LEXICAL 
NIL 
like image 40
Asai Masataro Avatar answered Oct 14 '22 21:10

Asai Masataro