Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is SBCL complaining about setf?

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?

like image 730
Franklin Einspruch Avatar asked Apr 28 '20 23:04

Franklin Einspruch


2 Answers

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.

like image 73
Phoebe Goldman Avatar answered Feb 02 '23 07:02

Phoebe Goldman


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:

defvar, defparameter

defparameter and defvar establish name as a dynamic variable.

Reference: http://clhs.lisp.se/Body/m_defpar.htm

let, let*

let and let* 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

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.

like image 28
digikar Avatar answered Feb 02 '23 07:02

digikar