Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How come (let ((x 'huh?)) (cons (boundp 'x) x)) evaluates to (NIL . HUH?)?

Tags:

common-lisp

I do not understand this:

CL-USER> (let ((x 'huh?)) (cons (boundp 'x) x))
(NIL . HUH?)

I had expected that inside the let expression above, x would be bound, and therefore that the whole expression would have evaluated to (t . huh?). Or else, if (contrary to my expectation) x was not bound in the let's body, then at least that the evaluation of the expression above would have resulted in an error (on account of my having passed an unbound variable as the second argument to cons).

To add to my confusion, the Common Lisp HyperSpec's description for boundp says:

Returns true if symbol is bound; otherwise, returns false.

...where the word "bound" is hyperlinked to this glossary definition (my emphasis)1:

bound adj., v.t. 1. adj. having an associated denotation in a binding. ``The variables named by a let are bound within its body.'' See unbound. 2. adj. having a local binding which shadows[2] another. ``The variable print-escape is bound while in the princ function.'' 3. v.t. the past tense of bind.

Furthermore, the CLHS's documentation for let says the following (my emphasis):

...all of the variables varj are bound to the corresponding values; ...

Granted, the HyperSpec's page for boundp (which I already linked to earlier) also has the following example:

(let ((x 2)) (boundp 'x)) =>  false

...which indeed would justify the assertion that what I observed is in fact "officially documented behavior", but this narrowly correct justification is little comfort in light of everything else I've cited above.

Could someone please resolve for me this whopping (and hopefully only apparent) contradiction?


1 I realize that the highlighted phrase above is just an example of how the word "bound" would be used in a sentence, but it would be a truly perverse example if what it stated was exactly the opposite of what is actually the case for Common Lisp.

like image 932
kjo Avatar asked Dec 22 '22 15:12

kjo


2 Answers

This can be a bit confusing, the spec for BOUNDP does however say that:

The function bound [sic (it should be boundp)] determines only whether a symbol has a value in the global environment; any lexical bindings are ignored.

So it only informs you if a given symbol is bound in the global environment, which happens if the variable has its value cell set to a value (see SYMBOL-VALUE), or the variable is declared special and was previously bound by a let form. This second case happens notably for variables declared with defvar and defparameter, but also any variable you declare as special:

(let ((%my-var% 0))
  (declare (special %my-var%))
  ...)

Note that to each time you want to use %my-var% you need to use that declaration, except if you declaimed it globally.

(defun use-my-var (input)
  (declare (special %my-var%))
  (print `(:my-var ,%my-var% :input ,input)))

When you write the use-my-var function, you have normally no problem identifying that input is bound, in fact a compiler would warn you if that was not the case. For lexical scopes, (boundp x) would compile down to a constant value, T or NIL. It is more interesting to check if the symbol-value of a symbol is globally bound or dynamically bound.

Here above, since %my-var% is a special variable, it can be bound or not in different calling contexts:

(let ((%my-var% 0))
  (declare (special %my-var%))
  (use-my-var 1))
=> (:my-var 0 :input 1)

(use-my-var 0)
;; ERROR: The variable %MY-VAR% is unbound.
like image 138
coredump Avatar answered Dec 29 '22 00:12

coredump


boundp is for determining whether symbols are bound in the global environment. Note the following two examples from the HyperSpec:

(let ((x 2)) (boundp 'x)) ;=>  false  
(let ((x 2)) (declare (special x)) (boundp 'x)) ;=>  true

The notes at the bottom of the page say:

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

The appearance of bound in the note instead of boundp seems to be a typo. In any case, CLTL2 was a bit more specific about this:

boundp is true if the dynamic (special) variable named by symbol has a value; otherwise, it returns nil.

Note that fboundp has a similar restriction; here is an example from the HyperSpec:

(flet ((my-function (x) x))  
  (fboundp 'my-function)) ;=>  false

There isn't much point in boundp handling lexical variables. From the HyperSpec 3.1.2.1.1.1 Lexical Variables:

A lexical variable always has a value. There is no operator that introduces a binding for a lexical variable without giving it an initial value, nor is there any operator that can make a lexical variable be unbound.

This is to say that lexical variables are always bound in their lexical environments. But dynamic variables may be either bound or unbound, and which of the two is the case can depend upon the environment in which the question is asked:

The value part of the binding for a dynamic variable might be empty; in this case, the dynamic variable is said to have no value, or to be unbound. A dynamic variable can be made unbound by using makunbound....

A dynamic variable is unbound unless and until explicitly assigned a value, except for those variables whose initial value is defined in this specification or by an implementation.

like image 36
ad absurdum Avatar answered Dec 28 '22 23:12

ad absurdum