Estou me ensinando um pouco mais sobre elisp e encontrei o seguinte problema:
Se eu quiser redefinir uma variável de lista, ela não será atualizada após a primeira avaliação. Aqui está um exemplo de código:
(defun initilize ()
(setq example '(3)))
(defun modify ()
(initilize)
(message "%S" example)
(setcar example 2))
; M-x eval-buffer RET
(modify) ; message --> (3)
(modify) ; message --> (2)
(modify) ; message --> (2)
Estou interessado em duas coisas. A primeira é aprender mais sobre o que está acontecendo "oculto", então por que funciona pela primeira vez e falha nas chamadas subseqüentes?
A segunda e mais prática questão é como reinicializar a lista corretamente ou existe outra maneira comum de fazer algo assim?
Uma solução alternativa que encontrei é usar uma lista citada e avaliar o conteúdo assim:
(setq example `(,3))
list
quote
mutability
clemera
fonte
fonte
'(some list)
para sereq
a'(some list)
- sempre .Não é geralmente nenhuma garantia em Lisp que o código que visivelmente cita uma lista de retornos nova estrutura de lista de cada vez. Em algumas implementações do Lisp, pode ser, ou pode ser por algumas vezes. Em outros, isso nunca acontece. De qualquer forma, seu código não deve depender de nenhum comportamento da implementação. Se você deseja uma nova estrutura de lista, uselist
oucons
ou equivalente.example
nunca foi declarado como uma variável, entãosetq
deve estar agindo como se declarasse uma nova variável, mas mais tarde, quando você ligarinitialize
novamente, uma nova variável está sendo criada, enquanto semodify
lembra da antiga ... em qualquer caso, esse não é um comportamento esperado; no entanto, o uso desetq
algo que não foi introduzido anteriormente como uma variável também pode ser indefinido.'(3)
é tratado como um valor literal, uma vez que você(setcar '(3) 2)
, sempre que você fizer(defvar foo '(3))
ou(let ((foo '(3)))
e assim por diante você provavelmente irá obter um valor defoo
igual'(2)
. Eu digo "provável" porque esse comportamento não é garantido, é um tipo de otimização que o intérprete faz sempre que parece, algo conhecido como eliminação de subexpressão de constantes (um caso específico de). Então, o que abo-abo escreveu não é exatamente o motivo. É mais como modificar uma string literal em C (que geralmente gera um aviso).Respostas:
Talvez isso esclareça parte da confusão:
Sua função
initilize
não inicializa variávelexample
. Ele o define como uma célula de contras específica - a mesma célula de contras cada vez que é chamada. Na primeira vez queinitilize
é chamado, elesetq
atribuiexample
a uma nova célula de contras, que é o resultado da avaliação'(3)
. Chamadas subsequentes parainitilize
reatribuirexample
à mesma célula de contras.Como
initilize
apenas reatribui a mesma célula de contrasexample
,modify
apenas define o carro dessa mesma célula de contras a2
cada vez que é chamada.Para inicializar uma lista, use
list
oucons
(ou um sexp equivalente de uma cota posterior, como`(,(+ 2 1))
ou`(,3)
). Por exemplo, use(list 3)
.A chave para entender isso é saber que uma célula de contras citada é avaliada apenas uma vez e, em seguida, a mesma célula de contras é retornada. Não é necessariamente assim que todos os Lisps se comportam, mas é como o Emacs Lisp se comporta.
De um modo mais geral, o comportamento de avaliar um objeto mutável citado depende da implementação, se não da linguagem. No Common Lisp, por exemplo, tenho certeza de que não há nada na definição (especificação) da linguagem que defina o comportamento a esse respeito - isso fica por conta da implementação.
Resumo: Não espere que '(alguma lista) seja igual a' (alguma lista) - sempre. Geralmente, não há garantia no Lisp de que o código que cita visivelmente uma lista retorne sempre uma nova estrutura de lista. Em algumas implementações do Lisp, pode ser, ou pode ser por algumas vezes. Em outros, isso nunca acontece. De qualquer forma, seu código não deve depender de nenhum comportamento da implementação. Se você deseja uma nova estrutura de lista, use
list
oucons
ou equivalente.fonte
Você pode usar
(setq example (list 3))
para evitar esse erro.O que acontece é
init
atribui um objeto que inicialmente contém(3)
aexample
. Ele define o valor do objeto apenas uma vez. Posteriormente, você modifica esse valor.Aqui está o seu exemplo em C ++, se você entender isso melhor:
fonte
initilize
função e ligarmodify
novamente, ela será exibida(3)
novamente apenas porque reavaliei a função.(3)
que é um objeto temporário do qual faz parteinit
.init
O corpo do conjuntoexample
é o endereço desse objeto temporário, ele não toca em seu valor.