Implicitly defined variables in Lisp and symbol tables - common-lisp

Suppose one introduces variables in a fresh Common Lisp
at the REPL and one types: (setq q 2).
I understand from these columns that this variable q is
not defined following the Common Lisp standard and
depends upon the implementation.
My question is: what is the easiest way or test to be
sure what it is exactly?
I read in one source that q is then automatically an implicitly defined
global dynamic variable and is then equivalent to
(defpar q 2).
In relation with this question. Seasoned Lisp
programmers talk much about the symbol tables. I do
not find in e.g. Seibel how to find out what is in
those tables. Can one access these tables? Do
debuggers support accessing these tables in a non
standard way?

Using SETQ rather than DEFPARAMETER is likely to make a global variable, but not a special variable. That will cause annoying debugging later. Don't use SETQ to define variables.
An example with lengthy code snippets. I'm using non-standard SBCL for this.
Let's define a package with two variables, one defined with DEFPARAMETER and one set with SETQ.
CL-USER> (defpackage :foo (:use :cl))
#<PACKAGE "FOO">
CL-USER> (in-package :foo)
#<PACKAGE "FOO">
FOO> (defparameter q 2)
Q
FOO> (setq w 2)
; in: SETQ W
; (SETQ FOO::W 2)
;
; caught WARNING:
; undefined variable: W
;
; compilation unit finished
; Undefined variable:
; W
; caught 1 WARNING condition
2 (2 bits, #x2, #o2, #b10)
FOO> q
2 (2 bits, #x2, #o2, #b10)
FOO> w
2 (2 bits, #x2, #o2, #b10)
The warning message already tells us that SBCL doesn't like the SETQ option, but the variable seems to work. Let's try to DESCRIBE the variables:
FOO> (describe 'q)
FOO::Q
[symbol]
Q names a special variable:
Value: 2
; No values
FOO> (describe 'w)
FOO::W
[symbol]
W names an undefined variable:
Value: 2
; No values
This says that Q is a special variable, while W is an undefined variable.
FOO> (sb-cltl2:variable-information 'q)
:SPECIAL
NIL
NIL
FOO> (sb-cltl2:variable-information 'w)
NIL
NIL
NIL
This also confirms that W is not a special variable like Q is. So what does this mean? Let's define a function that uses those variables:
FOO> (defun foobar ()
(format t "~&Q: ~a~%W: ~a~%" q w))
; in: DEFUN FOOBAR
; (FORMAT T "~&Q: ~a~%W: ~a~%" FOO::Q FOO::W)
;
; caught WARNING:
; undefined variable: W
;
; compilation unit finished
; Undefined variable:
; W
; caught 1 WARNING condition
FOOBAR
FOO> (foobar)
Q: 2
W: 2
NIL
Again we get warnings about W, but the code still seems to work. Let's try to shadow the variables.
FOO> (defun quux ()
(let ((q 100)
(w 100))
(foobar)))
; in: DEFUN QUUX
; (LET ((FOO::Q 100) (FOO::W 100))
; (FOO::FOOBAR))
;
; caught STYLE-WARNING:
; The variable W is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
QUUX
FOO> (quux)
Q: 100
W: 2
NIL
Now we notice that since W is not special, you can't shadow it. Also
FOO> (sb-introspect:who-binds 'q)
((QUUX
. #S(SB-INTROSPECT:DEFINITION-SOURCE
:PATHNAME NIL
:FORM-PATH (0 3 2)
:FORM-NUMBER 0
:CHARACTER-OFFSET 0
:FILE-WRITE-DATE NIL
:PLIST NIL
:DESCRIPTION NIL)))
FOO> (sb-introspect:who-binds 'w)
NIL
We can't see who binds the variable. Or who sets either:
FOO> (defun qwerty ()
(setf w 1000
q 1000))
; in: DEFUN QWERTY
; (SETF FOO::W 1000
; FOO::Q 1000)
; --> PROGN SETF
; ==>
; (SETQ FOO::W 1000)
;
; caught WARNING:
; undefined variable: W
;
; compilation unit finished
; Undefined variable:
; W
; caught 1 WARNING condition
QWERTY
FOO> (qwerty)
1000 (10 bits, #x3E8)
FOO> (sb-introspect:who-sets 'q)
((QWERTY
. #S(SB-INTROSPECT:DEFINITION-SOURCE
:PATHNAME NIL
:FORM-PATH (0 3 2)
:FORM-NUMBER 0
:CHARACTER-OFFSET 0
:FILE-WRITE-DATE NIL
:PLIST NIL
:DESCRIPTION NIL)))
FOO> (sb-introspect:who-sets 'w)
NIL
Since you also asked about symbol tables, the easiest way to see what's in it is to INSPECT a package. You can do that with your IDE (in Slime C-c I) or by calling the function directly:
FOO> (inspect (find-package :foo))
The object is a STRUCTURE-OBJECT of type PACKAGE.
0. %NAME: "FOO"
1. %NICKNAMES: NIL
2. %USE-LIST: (#<PACKAGE "COMMON-LISP">)
3. TABLES: #(#<SB-INT:PACKAGE-HASHTABLE
(978+0)/1973 [2.270 words/sym,load=49.6%] {100001A483}>)
4. MRU-TABLE-INDEX: 0
5. %USED-BY-LIST: NIL
6. INTERNAL-SYMBOLS: #<SB-INT:PACKAGE-HASHTABLE (7+0)/17 [2.732 words/sym,load=41.2%] {1006D60AE3}>
7. EXTERNAL-SYMBOLS: #<SB-INT:PACKAGE-HASHTABLE (0+0)/3 [load=0.0%] {1006D60B13}>
8. %SHADOWING-SYMBOLS: NIL
9. DOC-STRING: NIL
10. LOCK: NIL
11. %IMPLEMENTATION-PACKAGES: (#<PACKAGE "FOO">)
12. SOURCE-LOCATION: #S(SB-C:DEFINITION-SOURCE-LOCATION
:NAMESTRING NIL
:TOPLEVEL-FORM-NUMBER NIL
:FORM-NUMBER NIL
:PLIST NIL)
13. %LOCAL-NICKNAMES: NIL
14. %LOCALLY-NICKNAMED-BY: NIL
> 6
The object is a STRUCTURE-OBJECT of type SB-INT:PACKAGE-HASHTABLE.
0. CELLS: #(FOOBAR 0 QUUX ? 0 0 0 E W 0 Q QWERTY 0 0 0 0 0
#(21 0 98 59 0 0 0 223 135 0 193 37 0 0 0 0 0))
1. SIZE: 12
2. FREE: 5
3. DELETED: 0
> 0
The object is a VECTOR of length 18.
0. FOOBAR
1. 0
2. QUUX
3. ?
4. 0
5. 0
6. 0
7. E
8. W
9. 0
10. Q
11. QWERTY
12. 0
13. 0
14. 0
15. 0
16. 0
17. #(21 0 98 59 0 0 0 223 135 0 193 37 0 0 0 0 0)
> 8
The object is a SYMBOL.
0. Name: "W"
1. Package: #<PACKAGE "FOO">
2. Value: 1000
3. Function: "unbound"
4. Plist: NIL
> u
The object is a VECTOR of length 18.
0. FOOBAR
1. 0
2. QUUX
3. ?
4. 0
5. 0
6. 0
7. E
8. W
9. 0
10. Q
11. QWERTY
12. U
13. 0
14. 0
15. 0
16. 0
17. #(21 0 98 59 0 0 0 223 135 0 193 37 201 0 0 0 0)
> 10
The object is a SYMBOL.
0. Name: "Q"
1. Package: #<PACKAGE "FOO">
2. Value: 1000
3. Function: "unbound"
4. Plist: NIL
> q
You could also use DO-SYMBOLS to loop over symbols in a package.
FOO> (do-symbols (symbol)
(when (and (boundp symbol)
(eq (symbol-package symbol) *package*))
(format t "~&~a~% Value: ~a~% Info: ~a~% Who sets: ~a~% ~
Who binds: ~a~% Plist: ~a~% Documentation: ~a~%~%"
symbol
(symbol-value symbol)
(multiple-value-list
(sb-cltl2:variable-information symbol))
(sb-introspect:who-sets symbol)
(sb-introspect:who-binds symbol)
(symbol-plist symbol)
(documentation symbol 'variable))))
Q
Value: 1000
Info: (SPECIAL NIL NIL)
Who sets: ((QWERTY
. #S(SB-INTROSPECT:DEFINITION-SOURCE
:PATHNAME NIL
:FORM-PATH (0 3 2)
:FORM-NUMBER 0
:CHARACTER-OFFSET 0
:FILE-WRITE-DATE NIL
:PLIST NIL
:DESCRIPTION NIL)))
Who binds: ((QUUX
. #S(SB-INTROSPECT:DEFINITION-SOURCE
:PATHNAME NIL
:FORM-PATH (0 3 2)
:FORM-NUMBER 0
:CHARACTER-OFFSET 0
:FILE-WRITE-DATE NIL
:PLIST NIL
:DESCRIPTION NIL)))
Plist: NIL
Documentation: NIL
W
Value: 1000
Info: (NIL NIL NIL)
Who sets: NIL
Who binds: NIL
Plist: NIL
Documentation: NIL

Related

Function in LISP replacing every non-number in a list/sublist with NIL

I am trying to self-learn LISP programming. I'm having difficulty writing a LISP function that replaces every non-number in a list or sublist with NIL.
For example, if I input (REPLACE '(4 0 4)) it should return (4 0 4).
If I input (REPLACE '(1 2 SHOE (3 4 DOOR))) it should return (1 2 NIL (3 4 NIL))
I'm a bit stuck... how would this be done? Any help would be greatly appreciated!
EDIT: I don't have much, unfortunately, but so far, I have:
(defun REPLACE (L)
(cond ( (NUMBERP L)
I know I'd need to check to see if each element in the list is a number using NUMBERP. If anyone could help explain to me how to go from here so I can progress that'd be so helpful.
You need to split the problem up in steps:
A function that replaces non numbers with nil:
(defun (nil-non-number v)
...)
(nil-non-number 3) ; ==> 3
(nil-non-number 'q) ; ==> nil
(nil-non-number "test") ; ==> nil
A function that iterates a list and uses nil-non-number for each element:
(defun replace-non-nums (lst)
...)
(replace-non-nums '()) ; ==> nil
(replace-non-nums '(4 0 4)) ; ==> (4 0 4)
(replace-non-nums '(4 a 4)) ; ==> (4 nil 4)
(replace-non-nums '(1 2 shoe (3 4 door))) ; ==> (1 2 nil nil)
As a last step you need at add a test for cons before testing for non numbers and if it is you should also call replace-non-nums for that list and use the return there as the element. Then you can test the last one again:
(replace-non-nums '(1 2 shoe (3 4 door))) ; ==> (1 2 nil (3 4 nil))
All the other tests should yield the same as before as well.

Checking For A Compiler Optimization in SBCL

Is there a way to tell if SBCL has applied an optimization to a particular piece of source code? For example, on entering the following I would expect the case statement to be optimized into (print "0"):
(defconstant +n+ 0)
(case +n+
(0 (print "0"))
(1 (print "1")))
But expanding gives something different:
* (macroexpand '(case +n+ (0 (print "0")) (1 (print "1"))))
(LET ((#:G415 +N+))
(DECLARE (IGNORABLE #:G415))
(COND ((EQL #:G415 '0) NIL (PRINT "0")) ((EQL #:G415 '1) NIL (PRINT "1"))))
This is probably an unusual example, but how would one check for an optimization, in general.
As explained by Rainer Joswig, one possibility is to check for the disassembly. For example, with SBCL:
CL-USER> (defconstant +n+ 0)
"0"
"0"
CL-USER> (disassemble (compile nil (lambda () (case +n+
(0 (print "0"))
(1 (print "1"))))))
The above outputs this, which shows that the code has been simplified:
; disassembly for (LAMBDA ())
; Size: 32 bytes. Origin: #x52E552CC ; (LAMBDA ())
; CC: 498B4510 MOV RAX, [R13+16] ; thread.binding-stack-pointer
; D0: 488945F8 MOV [RBP-8], RAX
; D4: 488B15B5FFFFFF MOV RDX, [RIP-75] ; "0"
; DB: B902000000 MOV ECX, 2
; E0: FF7508 PUSH QWORD PTR [RBP+8]
; E3: B8A2324950 MOV EAX, #x504932A2 ; #<FDEFN PRINT>
; E8: FFE0 JMP RAX
; EA: CC10 INT3 16 ; Invalid argument count trap
NIL
There is also the possibility to show how the compiler is configured:
CL-USER> (sb-ext:describe-compiler-policy)
Basic qualities:
COMPILATION-SPEED = 1
DEBUG = 1
SAFETY = 1
SPACE = 1
SPEED = 1
INHIBIT-WARNINGS = 1
Dependent qualities:
SB-C::CHECK-CONSTANT-MODIFICATION = 1 -> 1 (maybe)
SB-C::TYPE-CHECK = 1 -> 3 (full)
SB-C::CHECK-TAG-EXISTENCE = 1 -> 3 (yes)
SB-C::LET-CONVERSION = 1 -> 3 (on)
SB-C:ALIEN-FUNCALL-SAVES-FP-AND-PC = 1 -> 3 (yes)
SB-C:VERIFY-ARG-COUNT = 1 -> 3 (yes)
SB-C::INSERT-DEBUG-CATCH = 1 -> 1 (maybe)
SB-C::RECOGNIZE-SELF-CALLS = 1 -> 0 (no)
SB-C::FLOAT-ACCURACY = 1 -> 3 (full)
SB-C:INSERT-STEP-CONDITIONS = 1 -> 0 (no)
SB-C::COMPUTE-DEBUG-FUN = 1 -> 1 (yes)
SB-C:STORE-SOURCE-FORM = 1 -> 1 (maybe)
SB-C::PRESERVE-SINGLE-USE-DEBUG-VARIABLES = 1 -> 0 (no)
SB-C::INSERT-ARRAY-BOUNDS-CHECKS = 1 -> 3 (yes)
SB-C::STORE-XREF-DATA = 1 -> 3 (yes)
SB-C:STORE-COVERAGE-DATA = 1 -> 0 (no)
SB-C::INSTRUMENT-CONSING = 1 -> 1 (no)
SB-C::STORE-CLOSURE-DEBUG-POINTER = 1 -> 0 (no)
SB-KERNEL:ALLOW-NON-RETURNING-TAIL-CALL = 1 -> 0 (no)

Clisp error : Variable has no value (In this Binary search program high and low has no value)

Simple program for binary search.
elements contain no. of elements
then array contains those elements
then q contains no. of queries
search contains element to be searched.
Why this error is coming about high and low has no value after some iterations.
Kindly help :)
My Code :-
(setf elements (parse-integer (read-line)))
(setf array (make-array elements :fill-pointer 0))
(dotimes (i elements) (vector-push (parse-integer (read-line)) array))
(setf q (parse-integer (read-line)))
(defvar *mid*)
(dotimes (i q)
(setf search (parse-integer (read-line)))
(do ((low 0)
(high (- elements 1))
(mid (floor (+ low high) 2)
(floor (+ low high) 2)))
((>= low high) (setf *mid* nil))
(cond
((eql (elt array mid) search) (setf *mid* mid))
((< (elt array mid) search) (setf high (- mid 1)))
(t (setf low (+ mid 1)))))
(format t "~a" *mid*))
Your code is a fine example of an old adage:
the determined Real Programmer can write FORTRAN programs in any language.
Unfortunately Lisp programmers are generally quiche-eating hippies: so here is one quiche-eater's solution to this problem, using notions not present when FORTRAN IV was handed down to us from above on punched stones. These notions are therefore clearly heretical, but nonetheless useful.
Assuming this is homework, you probably will not be able to submit this answer.
Reading the data
First of all we'll write some functions which read the specification of the problem from a stream or file. I have inferred what it is from your code.
(defun stream->search-spec (stream)
;; Read a search vector from a stream: return a vector to be searched
;; and a vector of elements to search for.
;;
;; This function defines what is in files: each line contains an
;; integer, and the file contains a count followed by that many
;; lines, which specifies first the vector to be searched, and then
;; the things to search for.
;;
;; This relies on PARSE-INTEGER & READ-LINE to puke appropriately.
(flet ((read-vector ()
(let* ((elts (parse-integer (read-line stream)))
(vec (make-array elts :element-type 'integer))) ;won't help
(dotimes (i elts vec)
(setf (aref vec i) (parse-integer (read-line stream)))))))
(values (read-vector) (read-vector))))
(defun file->search-spec (file)
;; Read a search vector from a file. This is unused below but is
;; useful to have.
(with-open-file (in file)
(stream->search-spec in)))
(defun validate-sorted-vector (v)
;; check that V is a sorted vector
(dotimes (i (- (length v) 1) v)
(unless (<= (aref v i) (aref v (1+ i)))
(return-from validate-sorted-vector nil))))
The last function is used below to sanity check the data, since the search algorithm assumes the vector is sorted.
The search function
This implements binary search in the same way yours tries to do. Rather than doing it with loops and explicit assignemnt it does it using a local recursive function, which is far easier to understand. There are also various sanity checks and optionally debugging output. In any implementation which optimises tail calls this will be optimised to a loop; in implementations which don't then there will be a few extra function calls but stack overflow problems are very unlikely (think about why: how big would the vector need to be?).
(defun search-sorted-vector-for (vector for &key (debug nil))
;; search a sorted vector for some value. If DEBUG is true then
;; print what we're doing. Return the index, or NIL if FOR is not
;; present.
(when debug
(format *debug-io* "~&* ~D:~%" for))
(labels ((search (low mid high)
(when debug
(format *debug-io* "~& ~10D ~10D ~10D~%" low mid high))
(if (<= low mid high)
;; more to do
(let ((candidate (aref vector mid)))
(cond ((= candidate for)
;; found it
mid)
((< candidate for)
;; look higher
(search (1+ mid) (floor (+ high mid 1) 2) high))
((> candidate for)
;; look lower
(search low (floor (+ low mid) 2) (1- mid)))
(t
;; can't happen
(error "mutant death"))))
;; low = high: failed
nil)))
(let ((high (1- (length vector))))
(search 0 (floor high 2) high))))
Putting the previous two things together.
search-sorted-vector-with-search-vector will repeatedly search using the two vectors that the *->search-spec functions return. stream->search-results uses stream->search-spec and then calls this on its values. file->search-results does it all from a file.
(defun search-sorted-vector-with-search-vector (vector searches &key (debug nil))
;; do a bunch of searches, returning a vector of results.
(let ((results (make-array (length searches))))
(dotimes (i (length searches) results)
(setf (aref results i) (search-sorted-vector vector (aref searches i)
:debug debug)))))
(defun stream->search-results (stream &key (debug nil))
;; Read search specs from a stream, and search according to them.
;; Return the vector of results, the vector being searched and the
;; vector of search specifications.
(multiple-value-bind (to-search search-specs) (stream->search-spec stream)
(when debug
(format *debug-io* "~&searching ~S~% for ~S~&" to-search search-specs))
(assert (validate-sorted-vector to-search) (to-search) "not sorted")
(values (search-sorted-vector-with-search-vector to-search search-specs
:debug debug)
to-search search-specs)))
(defun file->search-results (file &key (debug nil))
;; sort from a file
(with-open-file (in file)
(stream->search-results in :debug debug)))
Using it
Given a file /tmp/x.dat with:
9
1
10
100
101
102
103
200
201
400
6
10
102
200
1
400
99
then:
> (file->search-results "/tmp/x.dat" :debug t)
searching #(1 10 100 101 102 103 200 201 400)
for #(10 102 200 1 400 99)
* 10:
0 4 8
0 2 3
0 1 1
* 102:
0 4 8
* 200:
0 4 8
5 6 8
* 1:
0 4 8
0 2 3
0 1 1
0 0 0
* 400:
0 4 8
5 6 8
7 7 8
8 8 8
* 99:
0 4 8
0 2 3
0 1 1
2 1 1
#(1 4 6 0 8 nil)
#(1 10 100 101 102 103 200 201 400)
#(10 102 200 1 400 99)
You can see that the last search failed (99 is not in the vector).

(push x nil) VS (push x place-that-stores-the-empty-list)

Why is it not possible to push directly on a list like '(1 2 3) or NIL?
Specifically:
Why is possible to do
> (let ((some-list nil))
(push 42 some-list))
(42)
but not to do something like
(push 42 nil)
or
(push 42 '(1 2 3))
What is the reasoning behind this implementation?
With macro push the second argument needs to be a place to be modified. Here are some examples:
Lets make two variables:
(defparameter *v* (list 2 4))
(defparameter *v-copy* *v*)
Then we push 0
(push 1 *v*) ; ==> (1 2 4)
*v-copy* ; ==> (2 4) (unaltered)
; the reason is that the variable is changed, not its value
(macroexpand '(push 1 v))
; ==> (setq v (cons 1 v))
push can use other things as second argument. Lets try a cons
(push 3 (cdr *v-copy*))
*v-copy* ; ==> (2 3 4)
; since the tail of *v* is the *v-copy* *v* is changed too
*v* ; ==> (1 2 3 4)
(macroexpand-1 '(push 2 (cdr *v-copy*)))
; ==> (rplacd v (cons 2 (cdr *v-copy*)))
If your examples were valid, what should it really have done? Lets do the nil first:
(macroexpand '(push 42 nil))
; ==> (setq nil (cons 42 nil))
This treats nil just as any other variable and if this worked nil would never be the empty list again. It would have been a list with one element, 42 and a different value than (). In Common Lisp nil is a constant and cannot be mutated. I've created a lisp once where nil was a variable like any other and a small typo redefined nil making the programs behave strange with no apparent reason.
Lets try your literal quoted list.
(macroexpand '(push 42 (quote (1 2 3))))
; ==> (let ((tmp (1 2 3)))
; (funcall #'(setf quote) (cons 42 'tmp) tmp))
It doesn't seem the push macro differentiates between special form quote and those types that has set their setf function. It won't work and it doesn't make sense. Anyway in the same manner as mutating the binding nil if this changed the literal data '(1 2 3) to '(43 1 2 3) would you then expect to get (43 1 2 3) every time you evaluated (1 2 3) from there on? I imagine that would be the only true effect of mutating a constant. If this was allowed you should be allowed to redefine 4 to be 5 so that evaluating 4 or (+ 2 2) shows the result 5.

N-Queens Scheme: trying to print out chessboard

It is working fine and I've checked manually that everything is running, but I now need to figure out how to print out the answer in a chessboard like fashion, where I have an nxn board of 0's and 1's, where 1's are the queens. I am using vectors and for example lets say I run nq-bt for a 5x5 board I get the answer: #(0 2 4 1 3)
nq-bt is the method that gives me the answer above
Here is my pseudocode for trying to get this to work:
(define (print-answer n)
(make n equal to the returned vector of method (nq-bt))
(loop until it hits end of the returned vector_length)
(set value equal to (vector ref of n (*variable used for first loop)))
(loop again the length of returned vector_length)
(print 0's until hits vector ref's value, then print 1, then print 0's till end of loop)
(print newline)))))
I know this is insane pseudocode, but my problem is that I'm not used to scheme and there isn't too much documentation on how I could do any of this. Any help would be greatly appreciated.
You didn't mention which Scheme interpreter you're using, so first I'll show you a generic solution that uses standard procedures. For starters, we must decide how are we going to loop over the vector (say, using named lets).
Also notice that I changed the input parameter, it's easier if we pass the board's solution, besides I don't see how you can use the size n of the board if nq-bt doesn't receive it as a parameter (I hope nq-bt isn't obtaining n from a global define, that wouldn't be right):
(define (print-answer board)
(let outer-loop ((i 0))
(cond ((< i (vector-length board))
(let ((queen (vector-ref board i)))
(let inner-loop ((j 0))
(cond ((< j (vector-length board))
(display (if (= queen j) 1 0))
(display " ")
(inner-loop (+ j 1))))))
(newline)
(outer-loop (+ i 1))))))
Now, if you're lucky and use Racket we can write a simpler and more idiomatic implementation without all the kludge of the previous solution:
(define (print-answer board)
(for ([i (in-range (vector-length board))])
(let ([queen (vector-ref board i)])
(for ([j (in-range (vector-length board))])
(printf "~a " (if (= queen j) 1 0))))
(newline)))
Either way we can call print-answer with the result returned by nq-bt. For example:
(print-answer '#(0 2 4 1 3))
1 0 0 0 0
0 0 1 0 0
0 0 0 0 1
0 1 0 0 0
0 0 0 1 0

Resources