Правая сторона также получает назначение - PullRequest
0 голосов
/ 23 апреля 2019

Непосредственно излагая проблему;Я назначаю 'temp' как * TEMP * в операторе let.Когда я это делаю, * TEMP * получает именно то, что 'temp' было назначено на каждой итерации.И я заканчиваю тем, что выдвигаю то же самое значение 'temp's в конце.Понятия не имею, почему, вы, ребята, имеете какое-то представление о том, как здесь все идет не так?

(defparameter *TEMP* `((key value)(key2 value2)(key3 x))
(defparameter *SYNS* NIL)
(defparameter *PUSH-HERE* NIL)

(dolist (i *matrix*)
  (dolist (j i)
    (if  (equal 'keyword (first j)) 
        (foo (second j))))       ;fills *SYNS*
  (let ((temp *TEMP*))
    ;(print *TEMP*) prints temps last assigned value?
    (set-key temp (get-key i))   ;gets key's value
    (set-key2 temp (get-key2 i)) ;gets key2's value    
    (loop while (not (equal 0 (length *SYNS*)))
          do (set-key3 temp (pop *syns*))
          (push temp *PUSH-HERE*))))

Результирующее значение становится таким:

 ((key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value))

вместо;

((key first-assigned-value)(key2 first-assigned-value)(key3 first-assigned-value)
 (key second-assigned-value)(key2 second-assigned-value)(key3 second-assigned-value)
 (key last-assigned-value)(key2 last-assigned-value)(key3 last-assigned-value))

Я пробовал печатать, и перед строкой push печатается temp, как я хочу, но после завершения всей итерации я получил непреднамеренный список, который я выложил выше.

Ответы [ 3 ]

2 голосов
/ 24 апреля 2019

Переменная - это поле, которое содержит значение. Ячейка минуса (например, начало списка, который вы помещаете в *temp*) - это место в памяти с некоторыми указателями. Когда вы делаете (let ((temp *temp*)) ..., вы заставляете переменную temp указывать на тот же бит памяти, что и *temp*, поэтому, когда вы изменяете эту структуру данных, вы модифицируете ту же самую память, на которую указывает *temp*.

Один из способов исправить ваш код - попытаться увидеть, как обычно пишутся программы на lisp, и сделать ваш код более похожим на него, вместо того, чтобы применять свои знания о том, как писать программы на C, для языка с совершенно другой семантикой (в частности, Common Lisp не имеет семантики значений, как C). Одним из улучшений было бы создание нужных вам данных вместо того, чтобы тыкать в них палочками для еды (например, set-key и друзья). Я не могу выполнить ваш код, потому что вы не предоставили минимальный исполняемый пример, но вы можете создать одну строку из желаемого результата, выполнив что-то вроде:

`((key ,what-you-want-for-first-value)
  (key2 ,second-value)
  (key3 ,third))

Это создаст новый объект в новой памяти.

2 голосов
/ 24 апреля 2019

Вы связываете адрес *temp* с temp. Я предполагаю set-key обновления temp как с rplaca или (setf (car place) value). Таким образом, вы изменяете *temp* также, так как это то же значение, что и temp. Каждый раунд вы перезаписываете temp , который является тем же адресом, который вы выдвигали в новый список, и, таким образом, получается 3 одинаковых подсписка, так как они одинаковы. Это также является нарушением Common Lisp, поскольку *temp* заключена в кавычки буквально и, следовательно, является константой данных. Он может вести себя по-разному в разных реализациях.

Вместо разрушительной операции вы можете выполнить неразрушающую операцию, которая создает новое значение, например. с substitute-if, затем обновите привязку:

(setf temp 
      (substitute-if (cons 'key 'new-value) 
                     (lambda (e) (eq e 'key)) 
                     temp
                     :key #'car))

Если вам все еще нужна мутация, вы можете обойтись без нее, используя copy-alist:

(let ((temp (copy-alist *temp*)))
  ...)
1 голос
/ 24 апреля 2019

Я назначаю 'temp' как * TEMP * в операторе let.Когда я это делаю, * TEMP * получает именно то, что 'temp' было присвоено на каждой итерации

Переменная temp получает то же значение, что и переменная *temp*.Точно такой же объект, если это список.*temp* не получает новое значение.

CL-USER 30 > (defvar *temp* '(1 2 3))
*TEMP*

CL-USER 31 > (let ((temp *temp*))
               (eq temp *temp*))
T
...