SBCL为什么抱怨setf?

时间:2020-04-28 23:15:19

标签: common-lisp sbcl

在SBCL中,这会将'bar分配给foo,并显示警告:

* (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
* 

以下内容来自图雷兹基。我将其键入“ 7.29.lisp”并保存。

(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)))

其中:

* (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] 

要使SBCL对这些任务感到满意,我需要了解什么?

2 个答案:

答案 0 :(得分:10)

第一个警告对我来说似乎很清楚,TBH。在(setf foo 'bar)中,未知foo是指变量。尚未通过lambdalet的形式将其本地绑定为词法变量,并且尚未通过defvar或{的形式将其全局绑定为特殊变量。 {1}}。如果您希望它以顶级形式出现,则应编写defparameter(请注意,通用的lisp约定是将特殊变量的名称括在耳罩中)。如果要在函数体内或在有限范围内执行此操作,则应执行(defparameter *foo* 'bar)

关于第二个问题,除了(let ((foo 'bar)) (do-stuff-with foo))没有绑定的事实之外,您还使用了错误的引号字符。 database不是ASCII单引号,因此被解析为符号。编译器将您的表单视为:,这不是有效的(setf database |’| ((b1 shape green) ...))表单。要解决此问题,请弄清楚如何键入字符setf,并且/或者不要将格式文档中的代码复制粘贴到纯文本文件中。

答案 1 :(得分:3)

Phoebe's answer进行了总结,但我想补充一下我发现缺少的内容。

在常见的Lisp中,与某些其他语言(如python)和其他某些语言(如C)不同,变量初始化和变量赋值之间存在区别。

使用defvardefparameter引入全局变量,而使用letlet*lambda等引入局部变量。但是,这不仅仅涉及全球性或本地性,请参见this question on dynamic vs lexical scoping

一旦通过上述方式介绍了变量,就可以使用setf进行赋值了。


CLHS中使用的适当术语是:

defvar,defparameter

defparameterdefvar将名称建立为动态变量。

参考:http://clhs.lisp.se/Body/m_defpar.htm

让我们*

letlet*创建新的变量绑定...

每个绑定都是词法的,除非有相反的特殊声明

参考:http://clhs.lisp.se/Body/s_let_l.htm#let

setf

setf将place的值更改为newvalue。

参考:http://clhs.lisp.se/Body/m_setf_.htm

编辑:考虑了@tfb的评论和CLHS。