Вопрос
Я пишу функцию для класса Clos, который меняет элемент списка объекта указанного класса.
У меня есть метод, который вернет обратный список, но как я могу установить список объекта в этот список? Могу ли я иметь переменную экземпляра в функции, которая хранит список, затем установите элемент на это? Или есть более простой способ?
Вот метод, как сейчас:
(defun my-reverse (lst)
(cond ((null lst) ‘())
(t (append (my-reverse (cdr lst)) (car lst)))))
Объект, который он проходит,-это (l my-list), а аксессуар будет тогда (My-list-ls l).
РЕДАКТИРОВАТЬ: понял, что cons
не работает на 2 списка.
РЕДАКТИРОВАТЬ2: Я полагаю, что правильный код будет:
(defun my-reverse (l my-list)
(cond ((null (my-list-ls l) ‘())
(t (setf (my-list-ls l) (append (my-reverse (cdr (my-list-ls l)))
(car (my-list-ls l)))))))
Решение
Если вы хотите изменить слот объекта, вам нужно передать этот объект самому объекту, а не только значение слота, который вы хотите изменить.
РЕДАКТИРОВАТЬ: Относительно редактирования 2 вопроса
Я предполагаю my-list
Имя класса, и вы на самом деле не хотите передать его функции, верно? В этом случае вы должны заменить defun
с defmethod
. Анкет Кроме того, должно быть лучше изменить экземпляр только один раз, после того, как вы изменили весь список, а не на каждом шаге. Вы можете использовать внутреннюю функцию для этого:
(defmethod my-reverse ((l my-list))
(labels ((inner (list acc)
(if (endp list)
acc
(inner (rest list) (cons (first list) acc)))))
(setf (my-list-ls l) (inner (my-list-ls l) ()))))
РЕДАКТИРОВАТЬ 2: Подробное объяснение
defmethod
является альтернативой для defun
Для определения (полиморфных) методов. Хотя, если вам не нужен полиморфизм, вы можете просто использовать (defun my-reverse (l)
для первой строки.
labels
для определений внутренней функции. Здесь он определяет внутреннюю функцию с именем inner
с двумя параметрами list
а также acc
. inner
это функция, которая выполняет фактическую реверсию, и это хвостовая функция, потому что реверсирование естественным образом идет с хвостовой рекурсией. (Он может построить свой результат с cons
и поэтому имеет линейную сложность, тогда как ваше решение требует append
и тем самым квадратичная сложность, потому что cons
сам по себе постоянно, но append
линейно.)
first
а также rest
просто альтернативные имена для car
а также cdr
, endp
в основном это просто альтернативное название для null
, с разницей, что endp
сигнализирует об ошибке, если ее аргумент на самом деле не является списком.
Наконец, последние вызовы строки inner
с исходным и пустым списком в качестве аргументов, и присваивает результат слоту (переменная экземпляра, как переменная экземпляра).