意外的数据持久性

我有一个七个整数的列表,最初都是0,我们称之为“数据”。 定期在运行我的程序的过程中,我想增加一个整数的值之一。 在程序结束时,我打印数据。 一切都很好,除了在程序的每次连续运行中,所有来自上次运行的数据值都会被添加到此运行的所有数据值中。 我只想要这个运行的数据值。 数据是类方法中的局部variables,类方法调用的单独函数中的局部variables或类的槽,会发生这种意外的行为。 我是否通过incf或(setf value(1+ value))递增数据的单个值。 当我重新加载程序时,数据重置为全零,但是当我再次运行程序时,数据再次将所有最后一次运行的数据添加到此运行的数据。 当我增加其中一个数据值时,我使用函数nth,index是另一个对象的插槽的值。 什么会导致我的“数据”列表的价值不受欢迎的持续存在?

你是否在做这样的事情:

CL-USER> (defun foo () (let ((value '(1))) ; '(1) is literal data (incf (car value)))) FOO CL-USER> (foo) 2 CL-USER> (foo) 3 CL-USER> (foo) 4 CL-USER> (foo) 5 

引用的数据是文字数据; 只有一个副本,修改它的后果是不确定的。 上面的行为是常见的,但是你不能依赖它。 当你这样做的时候一些编译器会发出警告。 例如,在SBCL中:

 CL-USER> (defun foo () (let ((value '(1))) (incf (car value)))) ; in: DEFUN FOO ; (INCF (CAR VALUE)) ; --> LET* ; ==> ; (SB-KERNEL:%RPLACA #:TMP1 #:NEW0) ; ; caught WARNING: ; Destructive function SB-KERNEL:%RPLACA called on constant data. ; See also: ; The ANSI Standard, Special Operator QUOTE ; The ANSI Standard, Section 3.2.2.3 ; ; compilation unit finished ; caught 1 WARNING condition FOO 

HyperSpec的相关quote是:

如果字面对象(包括带引号的对象)被破坏性地修改,结果是不确定的。

用例如(list 1)创build可修改的列表,而不是'(1) 。 直到遇到它,这是一个常见的陷阱。 在StackOverflow上还有一些其他的问题提到了这个问题。 一个非常具体的是

  • 为什么这个函数每次都返回一个不同的值?

但也有一堆:

  • LISP:为什么mapcan不能接受我的列表作为参数? (一个传递给mapcan的lambda函数内的文字列表的有趣案例)
  • 使用Common Lispsorting的意外列表复制
  • LISP – 全局variables在重新初始化后保持原有值
  • 这个答案给Sudoku表生成器失败,lisp
  • Lisp函数如何在这段代码中记住状态?
  • Common Lisp中的属性列表是指一些全局状态?
  • 为什么这个函数每次都返回一个不同的值?
  • 奇怪的行为调用破坏性的通用LISP函数接收作为参数用quote创build的列表
  • 局部variables保留以前执行的数据
  • 这个Common Lisp代码发生了什么?
  • 意外的数据持久性 (这个问题)
  • 函数中的setf不起作用
  • 在Lisp中复制和修改列表的头部

计划中也发生了同样的情况,尽pipe对文档的引用明显不同。 对于R 5 RS,文档如下:

4.1.2文字expression

…如第3.4节所述,使用像set-car这样的突变过程来改变常量(即文字expression式的值)是错误的! 或string设置!

3.4存储模式

…在许多系统中,常量(即文字expression式的值)需要驻留在只读存储器中。 为了expression这一点,可以很方便地想象,表示位置的每个对象都与一个标志相关联,以表明该对象是可变的还是不可变的。 在这样的系统中,字面常量和符号 – >string返回的string是不可变对象,而由此报告中列出的其他过程创build的所有对象都是可变的。 尝试将新值存储到由不可变对象表示的位置是错误的。

还有一些关于这个的问题:

  • 我怎么能解释我的Scheme代码的这种意外的行为?
  • '(())和(cons null null)之间的区别