In SBCL, this will assign 'bar
to foo
, with warnings:
* (setf foo 'bar)
; in: SETF FOO
; (SETF FOO 'BAR)
; ==>
; (SETQ FOO 'BAR)
;
; caught WARNING:
; undefined variable: COMMON-LISP-USER::FOO
;
; compilation unit finished
; Undefined variable:
; FOO
; caught 1 WARNING condition
BAR
*
The following is from Touretzky. I typed this into "7.29.lisp" and saved.
(setf database
’((b1 shape brick)
(b1 color green)
(b1 size small)
(b1 supported-by b2)
(b1 supported-by b3)
(b2 shape brick)
(b2 color red)
(b2 size small)
(b2 supports b1)
(b2 left-of b3)
(b3 shape brick)
(b3 color red)
(b3 size small)
(b3 supports b1)
(b3 right-of b2)
(b4 shape pyramid)
(b4 color blue)
(b4 size large)
(b4 supported-by b5)
(b5 shape cube)
(b5 color green)
(b5 size large)
(b5 supports b4)
(b6 shape brick)
(b6 color purple)
(b6 size large)))
Whereupon:
* (load "7.29.lisp")
While evaluating the form starting at line 1, column 0
of #P"/home/redacted/7.29.lisp":
debugger invoked on a SIMPLE-ERROR in thread
#<THREAD "main thread" RUNNING {10005D05B3}>:
odd number of args to SETF: (SETF DATABASE ’
((B1 SHAPE BRICK) (B1 COLOR GREEN)
(B1 SIZE SMALL) (B1 SUPPORTED-BY B2)
(B1 SUPPORTED-BY B3) (B2 SHAPE BRICK)
(B2 COLOR RED) (B2 SIZE SMALL)
(B2 SUPPORTS B1) (B2 LEFT-OF B3)
(B3 SHAPE BRICK) (B3 COLOR RED) ...))
Type HELP for debugger help, or (SB-EXT:EXIT) to exit from SBCL.
restarts (invokable by number or by possibly-abbreviated name):
0: [RETRY ] Retry EVAL of current toplevel form.
1: [CONTINUE] Ignore error and continue loading file "/home/redacted/7.29.lisp".
2: [ABORT ] Abort loading file "/home/redacted/7.29.lisp".
3: Exit debugger, returning to top level.
(SB-C::EXPLODE-SETQ (SETF DATABASE ’ ((B1 SHAPE BRICK) (B1 COLOR GREEN) (B1 SIZE SMALL) (B1 SUPPORTED-BY B2) (B1 SUPPORTED-BY B3) (B2 SHAPE BRICK) (B2 COLOR RED) (B2 SIZE SMALL) (B2 SUPPORTS B1) (B2 LEFT-OF B3) (B3 SHAPE BRICK) (B3 COLOR RED) ...)) ERROR)
0]
What do I need to understand to make SBCL happy with these assignments?
that first warning seems pretty clear to me, tbh. in (setf foo 'bar)
, foo
is not known to refer to a variable. it hasn't been locally bound as a lexical variable by a form like lambda
or let
, and it hasn't been globally bound as a special variable by a form like defvar
or defparameter
. if you want this to appear as a top-level form, you should write (defparameter *foo* 'bar)
(note that common lisp convention is to surround the names of special variables in earmuffs). if you want to do this within the body of a function or for a finite scope, you should do (let ((foo 'bar)) (do-stuff-with foo))
.
as to your second problem, in addition to the fact that database
is unbound, you have the wrong quote character. ’
is not an ascii single-quote, and as such, is being parsed as a symbol. the compiler sees your form as: (setf database |’| ((b1 shape green) ...))
, which is not a valid setf
form. to fix this, figure out how to type the character '
, and/or don't copy-paste code from formatted documents into plain text files.
While Phoebe's answer sums it up, I'd like to put some context that I find missing.
In common lisp, unlike some other languages (like python), and like some other languages (like C), there is distinction between variable initialization and variable assignment.
Global variables are introduced using defvar
, defparameter
, while local variables using let
, let*
, lambda
and the likes. However, it's not just about being global or local - see this question on dynamic vs lexical scoping.
Once, you have introduced the variables by the above means, you can use setf
for the assignment.
The proper terms used in the CLHS are:
defparameter
anddefvar
establish name as a dynamic variable.
Reference: http://clhs.lisp.se/Body/m_defpar.htm
let
andlet*
create new variable bindings...each binding is lexical unless there is a special declaration to the contrary
Reference: http://clhs.lisp.se/Body/s_let_l.htm#let
setf changes the value of place to be newvalue.
Reference: http://clhs.lisp.se/Body/m_setf_.htm
Edit: Took @tfb's comment and CLHS into account.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With