我正在关注有关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的正确方法是什么?
确实,这就是您要增加的方式x
,或者至少是这样做的一种方式。但是,这并不是您要绑定的方式x
。在CL中,您需要先使用名称建立绑定,然后再使用它,而不仅仅是通过分配它来实现。因此,例如,此代码(在新的CL图像中)不是合法的CL:
(defun bad ()
(setf y 2))
通常,这可能会导致编译时警告和运行时错误,尽管它可能还会执行其他操作:未定义其行为。
尤其是,您所做的实际上比这更糟:您将一个值添加到symbol-value
of中x
(使用set
,这样做),然后假定类似的东西(incf x)
会起作用,而这是极不可能的。例如考虑这样的事情:
(defun worse ()
(let ((x 2))
(set 'x 4)
(incf x)
(values x (symbol-value 'x))))
这是(不同于bad
)法律法规,但是它可能并没有按照您的意愿去做。
许多CL实现的确允许在顶层分配给以前未绑定的变量,因为在对话环境中它很方便。但是这种分配的确切含义超出了语言标准。
从历史上看,CMUCL及其衍生产品(包括SBCL)比当时的其他实现更加认真。我认为其原因是解释器比大多数其他解释器严重得多,并且/或者他们反正秘密地编译了所有内容,然后编译器将其拾起。
另一个问题是,CL对顶级变量的语义有些尴尬:如果您试图与defvar
&老友以正常方式建立顶级绑定,那么您还会导致变量是特殊的-动态范围- -这是普遍现象:它使该名称的所有绑定都变得特别。这通常是非常不希望的结果。作为一种语言,CL没有顶级词汇变量的概念。
因此,许多实现所做的就是要有某种非正式的概念,即对某事物的顶级绑定进行顶层绑定,这并不意味着要进行特殊声明:如果您只是(setf x 3)
在顶层进行说明,那么这将不会影响整个环境。但是随后出现了各种尴尬的问题:这样做之后(symbol-value 'x)
,例如,结果是什么?
幸运的是,CL是一种功能强大的语言,并且很有可能在该语言中定义顶级词汇变量。这是一个非常笨拙的实现,称为deflexical
。请注意,那里有更好的实现(至少包括我一个,目前无法找到):这并不是防弹解决方案。
(defmacro deflexical (var &optional value)
;; Define a cheap-and-nasty global lexical variable. In this
;; implementation, global lexicals are not boundp and the global
;; lexical value is not stored in the symbol-value of the symbol.
;;
;; This implementation is *not* properly thought-through and is
;; without question problematic
`(progn
(define-symbol-macro ,var (get ',var 'lexical-value))
(let ((flag (cons nil nil)))
;; assign a value only if there is not one already, like DEFVAR
(when (eq (get ',var 'lexical-value flag) flag)
(setf (get ',var 'lexical-value) ,value))
;; Return the symbol
',var)))
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句