为什么 SBCL 抱怨 setf?
Why is SBCL complaining about setf?
在 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 对这些作业感到满意?
第一个警告对我来说似乎很清楚,tbh。在 (setf foo 'bar)
中,foo
不知道引用变量。它没有被像 lambda
或 let
这样的形式局部绑定为词法变量,也没有被像 defvar
或 [= 这样的形式全局绑定为特殊变量=15=]。如果你想让它以顶级形式出现,你应该写 (defparameter *foo* 'bar)
(注意,常见的 lisp 约定是将特殊变量的名称包围在耳罩中)。如果您想在函数体内或有限范围内执行此操作,则应该执行 (let ((foo 'bar)) (do-stuff-with foo))
.
关于您的第二个问题,除了 database
未绑定之外,您的引号字符也有误。 ’
不是 ascii 单引号,因此被解析为符号。编译器将您的表单视为:(setf database |’| ((b1 shape green) ...))
,这不是有效的 setf
表单。要解决此问题,请弄清楚如何键入字符 '
,and/or 不要将格式化文档中的代码复制粘贴到纯文本文件中。
虽然 总结了它,但我想补充一些我发现缺失的上下文。
在普通的 lisp 中,不像其他一些语言(如 python),也像其他一些语言(如 C),变量初始化和变量赋值是有区别的。
全局变量使用defvar
、defparameter
引入,局部变量使用let
、let*
、lambda
等。然而,这不仅仅是关于全球或本地 - 请参阅 this question on dynamic vs lexical scoping.
一旦你通过上述方式引入了变量,就可以使用setf
进行赋值了。
CLHS 中使用的正确术语是:
defvar, defparameter
defparameter
and defvar
establish name as a dynamic variable.
参考:http://clhs.lisp.se/Body/m_defpar.htm
让,让*
let
and let*
create new variable bindings...
each binding is lexical unless there is a special declaration to the contrary
参考:http://clhs.lisp.se/Body/s_let_l.htm#let
setf
setf changes the value of place to be newvalue.
参考:http://clhs.lisp.se/Body/m_setf_.htm
编辑:考虑了@tfb 的评论和 CLHS。
在 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 对这些作业感到满意?
第一个警告对我来说似乎很清楚,tbh。在 (setf foo 'bar)
中,foo
不知道引用变量。它没有被像 lambda
或 let
这样的形式局部绑定为词法变量,也没有被像 defvar
或 [= 这样的形式全局绑定为特殊变量=15=]。如果你想让它以顶级形式出现,你应该写 (defparameter *foo* 'bar)
(注意,常见的 lisp 约定是将特殊变量的名称包围在耳罩中)。如果您想在函数体内或有限范围内执行此操作,则应该执行 (let ((foo 'bar)) (do-stuff-with foo))
.
关于您的第二个问题,除了 database
未绑定之外,您的引号字符也有误。 ’
不是 ascii 单引号,因此被解析为符号。编译器将您的表单视为:(setf database |’| ((b1 shape green) ...))
,这不是有效的 setf
表单。要解决此问题,请弄清楚如何键入字符 '
,and/or 不要将格式化文档中的代码复制粘贴到纯文本文件中。
虽然
在普通的 lisp 中,不像其他一些语言(如 python),也像其他一些语言(如 C),变量初始化和变量赋值是有区别的。
全局变量使用defvar
、defparameter
引入,局部变量使用let
、let*
、lambda
等。然而,这不仅仅是关于全球或本地 - 请参阅 this question on dynamic vs lexical scoping.
一旦你通过上述方式引入了变量,就可以使用setf
进行赋值了。
CLHS 中使用的正确术语是:
defvar, defparameter
defparameter
anddefvar
establish name as a dynamic variable.
参考: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
参考:http://clhs.lisp.se/Body/s_let_l.htm#let
setf
setf changes the value of place to be newvalue.
参考:http://clhs.lisp.se/Body/m_setf_.htm
编辑:考虑了@tfb 的评论和 CLHS。