我正在关注lisp的教程,他们做了以下代码
(set 'x 11)
(incf x 10)
和解释器给出了以下错误:
; in: INCF X
; (SETQ X #:NEW671)
;
; caught WARNING:
; undefined variable: X
;
; compilation unit finished
; Undefined variable:
; X
; caught 1 WARNING condition
21
增加x的正确方法是什么?
答案 0 :(得分:1)
这确实是你要增加x
的方式,或至少有一种方法。但是,你不应该如何绑定x
。在CL中,您需要在使用之前为名称建立绑定,而不是仅通过分配它来实现。因此,例如,此代码(在新的CL映像中)不合法CL:
(defun bad ()
(setf y 2))
通常这会导致编译时警告和运行时错误,尽管它可能会执行其他操作:未定义其行为。
你所做的事情,特别是,实际上比这更糟糕:你已经将一个值夯入了symbol-value
的{{1}}(x
,这样做了),然后假设像set
这样的东西会起作用,这是不可能的。例如,考虑这样的事情:
(incf x)
这是(与(defun worse ()
(let ((x 2))
(set 'x 4)
(incf x)
(values x (symbol-value 'x))))
)合法代码不同,但它可能无法按照您的意愿执行。
许多CL实现做允许在顶层分配以前未绑定的变量,因为在会话环境中它很方便。但这种作业的确切含义超出了语言标准。
CMUCL及其衍生产品,包括SBCL,在历史上比其他实施当时更加认真。我认为这样做的原因是解释器比其他大多数人更严重和/或他们秘密编译了所有内容并且编译器选择了。
另一个问题是CL对于顶级变量有一些稍微笨拙的语义:如果你努力以正常的方式建立一个顶层绑定,bad
&朋友们,那么你也会使变量成为特殊的 - 动态作用域 - 这是一种普遍的效果:它使该名称的所有绑定变得特别。这通常是一个非常不理想的后果。 CL作为一种语言,没有顶级词汇变量的概念。
因此,有许多实现方式是对某些东西的顶级绑定采取某种非正式概念,这并不意味着特殊声明:如果你只是在顶层说defvar
那么这就不会控制整个环境。但后来有各种各样的尴尬问题:在这之后,例如(setf x 3)
的结果是什么?
幸运的是,CL是一种功能强大的语言,很有可能定义语言中的顶级词汇变量。这是一个名为(symbol-value 'x)
的非常hacky实现。请注意,那里有更好的实现(包括我至少有一个,我现在找不到):这并不是一个防弹解决方案。
deflexical