Persistência inesperada de dados

Eu tenho uma lista de sete inteiros, inicialmente todos os 0s, vamos chamá-lo de “dados”. Periodicamente, durante a execução do meu programa, quero incrementar o valor de um desses números inteiros em um. No final do programa, imprimo dados. Tudo está bem, exceto que em cada execução sucessiva do programa todos os valores de dados da última execução são adicionados a todos os valores de dados dessa execução. Eu quero apenas os valores dos dados dessa execução. Esse comportamento inesperado ocorre se os dados são uma variável local dentro do método de uma class, uma variável local dentro de uma function separada chamada pelo método de uma class ou um slot de uma class. Acontece se eu incremento os valores individuais dos dados por incf ou (valor setf (valor 1+)). Quando eu recarrego o programa, os dados são redefinidos para todos os zeros, mas quando eu executo o programa novamente, os dados novamente adicionam todos os dados da última execução aos dados desta corrida. Quando eu incremento um dos valores de dados eu uso a function nth com o índice sendo o valor do slot de outro object. O que poderia causar essa persistência indesejada de valores da minha lista de “dados”?

    Você está fazendo algo assim:

    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 

    Dados citados são dados literais ; há apenas uma cópia dela e as conseqüências de modificá-la são indefinidas. O comportamento acima é comum, mas você não pode depender dele. Alguns compiladores darão um aviso quando você fizer isso. Por exemplo, em 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 

    O texto relevante do HyperSpec na quote é:

    As conseqüências são indefinidas se objects literais (incluindo objects citados) são modificados destrutivamente.

    Crie listas modificáveis ​​com, por exemplo, (list 1) , não '(1) . Essa é uma armadilha comum até que você a tenha encontrado. Existem algumas outras questões no StackOverflow que mencionam esse problema. Um muito específico é

    • Por que essa function retorna um valor diferente toda vez?

    mas também há um monte:

    • LISP: Por que o mapcan não aceita minha lista como parâmetros? (um caso interessante com uma lista literal dentro de uma function lambda passada ao mapcan )
    • Duplicação de lista inesperada usando Sort with Common Lisp
    • LISP – Variável global mantém seu valor antigo após reboot
    • esta resposta para a falha do gerador de tabela Sudoku, lisp
    • Como a function Lisp se lembra do estado neste código?
    • As listas de propriedades no Common Lisp se referem a algum estado global?
    • Por que essa function retorna um valor diferente toda vez?
    • Comportamento estranho invocando function Common LISP destrutiva recebendo como argumento uma lista criada com citação
    • Variável local mantém dados de execução anterior
    • O que está acontecendo com este código Common Lisp?
    • Persistência inesperada de dados (esta questão)
    • setf em uma function não funciona
    • duplicando e modificando a cabeça de uma lista de lista, em Lisp

    A mesma coisa acontece no Scheme, embora as citações à documentação sejam obviamente diferentes. Para o R5 RS, a documentação é a seguinte:

    4.1.2 Expressões Literal

    … Como observado na seção 3.4, é um erro alterar uma constante (ou seja, o valor de uma expressão literal) usando um procedimento de mutação como set-car! ou conjunto de strings.

    3.4 Modelo de Armazenamento

    … Em muitos sistemas, é desejável que as constantes (isto é, os valores das expressões literais) residam na memory somente leitura. Para expressar isso, é conveniente imaginar que todo object que denota localizações esteja associado a um sinalizador informando se esse object é mutável ou imutável. Em tais sistemas, as constantes literais e as strings retornadas por symbol-> string são objects imutáveis, enquanto todos os objects criados pelos outros procedimentos listados neste relatório são mutáveis. É um erro tentar armazenar um novo valor em um local denotado por um object imutável.

    Há perguntas sobre isso também:

    • Como eu poderia explicar esse comportamento inesperado do meu código Scheme?
    • Diferença entre ‘(()) e (cons null null)