Nano Hash - криптовалюты, майнинг, программирование

Изменение копий списков в LISP

В LISP у меня есть функция, которой передается список. Я хотел бы изменить элемент этого списка без изменения исходного списка. Обычно я бы использовал copy-list для создания локальной копии списка, которую я изменю, но это, похоже, не работает:

CL-USER> (defun test (item)
    (let ((copy (copy-list item)))
         (setf (nth 0 (nth 0 (nth 0 copy))) t)
         (print item)
         (print copy)))

CL-USER> (defparameter item `(((NIL NIL) (NIL NIL) (NIL NIL))
                     ((NIL NIL NIL) (NIL NIL NIL))
                     ((3 3) (NIL NIL))))

CL-USER> (test item)
(((T NIL) (NIL NIL) (NIL NIL)) ((NIL NIL NIL) (NIL NIL NIL)) ((3 3) (NIL NIL))) 
(((T NIL) (NIL NIL) (NIL NIL)) ((NIL NIL NIL) (NIL NIL NIL)) ((3 3) (NIL NIL))) 
(((T NIL) (NIL NIL) (NIL NIL)) ((NIL NIL NIL) (NIL NIL NIL)) ((3 3) (NIL NIL)))
CL-USER> item
(((T NIL) (NIL NIL) (NIL NIL)) ((NIL NIL NIL) (NIL NIL NIL)) ((3 3) (NIL NIL)))

Как видите, значение item было изменено на test, хотя я скопировал список в локальную переменную и изменил локальную копию. Похоже, это симптом использования nth. Если я использую один вызов car, а не повторный вызов nth, функция работает, как и ожидалось, и item после вызова не меняется.

Почему nth ведет себя так и как я могу продолжать использовать nth без изменения значения, переданного test?

Я использую Common Lisp.



Ответы:


1

Краткий ответ: используйте cl:copy-tree

Возможно, вы захотите скопировать все дерево с помощью copy-tree. Копия, сделанная с помощью copy-list, создает только новую "основу"; вы получите новый список, но с теми же элементами. Copy-tree скопирует всю структуру cons-tree, из которой состоит дерево.

Длинный ответ: структура списка против древовидной структуры

Фон здесь упоминается в документации. Из ГиперСпец:

Функция COPY-LIST

Копируется только структура списка; элементы результирующего списка такие же, как соответствующие элементы данного списка.

Эта запись глоссария для структуры списка важна:

структура списка мн. (списка) набор минусов, из которых состоит список. Обратите внимание, что хотя компонент автомобиля каждого такого минуса является частью структуры списка, объекты, которые являются элементами списка (т. е. объекты, которые являются автомобилями каждого минуса в списке), сами по себе не являются частью его структуры списка, даже если они являются минусами, за исключением (кругового) случая, когда список фактически содержит один из своих хвостов в качестве элемента. (Списковая структура списка иногда избыточно упоминается как его «структура списка верхнего уровня», чтобы подчеркнуть, что любые conses, которые являются элементами списка, не задействованы.)

В качестве очень простого примера мы можем использовать тот факт, что *print-circle* покажет нам общую подструктуру:

CL-USER> (setf *print-circle* t)
T

CL-USER> (let ((l '((a b c) (d e f))))
           (list l (copy-list l)))
;=> ((#1=(A B C) #2=(D E F)) (#1# #2#))

CL-USER> (let ((l '((a b c) (d e f))))
           (list l (copy-tree l)))
;=> (((A B C) (D E F)) ((A B C) (D E F)))

Запись HyperSpec в copy-tree не ссылается на древовидную структуру, но есть есть запись в глоссарии:

древовидная структура сущ. (дерева) набор минусов, из которых состоит дерево. Обратите внимание, что хотя компонент автомобиля каждого такого элемента cons является частью древовидной структуры, объекты, которые являются автомобилями каждого элемента cons в дереве, сами по себе не являются частью его древовидной структуры, если только они не являются также элементами cons.

Это второе предложение немного странное, но, вероятно, это просто минимально измененная копия и вставка записи list list. См. мой ответ на определение древовидная структура в Лиспе, чтобы узнать об этом подробнее.

07.11.2014
  • Это действительно запутанный язык: в то время как автомобильный компонент каждого такого минуса является частью структуры списка, объекты, которые являются автомобилями каждого минуса в списке, сами по себе не являются частью его структуры списка!!! 20.10.2020
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

    Понимание расстояния Вассерштейна: мощная метрика в машинном обучении
    В обширной области машинного обучения часто возникает необходимость сравнивать и измерять различия между распределениями вероятностей. Традиционные метрики расстояния, такие как евклидово..

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..


    © 2024 nano-hash.ru, Nano Hash - криптовалюты, майнинг, программирование