【问题标题】:sbcl Common Lisp incf warning [duplicate]sbcl Common Lisp incf 警告 [重复]
【发布时间】:2017-02-27 04:09:54
【问题描述】:

我正在关注一个关于 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 的正确方法是什么?

【问题讨论】:

    标签: lisp increment sbcl


    【解决方案1】:

    这确实是您要增加x 的方式,或者至少是这样做的一种方式。但是,这不是您要绑定x 的方式。在 CL 中,您需要在使用名称之前为它建立一个绑定,而不是仅仅通过分配给它来做到这一点。因此,例如,这段代码(在新的 CL 图像中)是不合法的 CL:

    (defun bad ()
      (setf y 2))
    

    通常这会导致编译时警告和运行时错误,尽管它可能会做其他事情:它的行为未定义。

    您所做的实际上比这更糟糕:您将一个值撞到了xsymbol-value 中(使用set,它执行此操作),然后假设类似@987654327 @ 将起作用,这是极不可能的。例如考虑这样的事情:

    (defun worse ()
      (let ((x 2))
        (set 'x 4)
        (incf x)
        (values x (symbol-value 'x))))
    

    这是(与bad 不同)合法代码,但它可能不会按照您的意愿行事。

    许多 CL 实现 确实 允许在顶层分配以前未绑定的变量,因为在会话环境中它很方便。但此类赋值的确切含义超出了语言标准。

    CMUCL 及其衍生产品(包括 SBCL)在历史上一直比当时的其他实现更加认真。我认为造成这种情况的原因是解释器比大多数其他人更严肃,并且/或者他们无论如何都秘密编译了所有内容,而编译器捡起了东西。

    另一个问题是 CL 对顶级变量的语义稍显尴尬:如果您努力以正常方式建立顶级绑定,使用 defvar 和朋友,那么您也会导致变量special -- 动态范围 -- 这是一种普遍的效果:它使 all 该名称的绑定变得特殊。这通常是一个非常不受欢迎的结果。 CL 作为一门语言,没有顶级词法变量的概念。

    因此,许多实现所做的就是对不暗示特殊声明的事物进行顶层绑定的某种非正式概念:如果您只是在顶层说(setf x 3),那么这不会传染整个环境。但随之而来的是各种尴尬的问题:这样做之后,比如(symbol-value 'x)的结果是什么?

    幸运的是,CL 是一门强大的语言,在语言中定义顶级词法变量是完全可能的。这是一个名为deflexical 的非常hacky 的实现。请注意,那里有更好的实现(包括我的至少一个,我现在找不到):这并不是一个防弹的解决方案。

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

    【讨论】:

    • 看起来我需要更多阅读。你能推荐一个好的来源吗?
    • @Hydrocat:我真的不是问这个问题的合适人选:当我学习 CL 时,实际上只有 CLtL(虽然是一本有趣的书),但它并不是真正的良好、当前信息的来源。我喜欢 Paul Graham 的书,我认为它现在是免费的,而规范则不好学。也许其他人有更好和更新的想法。
    • 哦,太好了 :) 我实际上得到了 Graham 的书。那么我应该得到很好的照顾!
    猜你喜欢
    • 2016-01-10
    • 2015-09-30
    • 2016-10-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-05-19
    • 1970-01-01
    相关资源
    最近更新 更多