Переменные экземпляра в Лиспе? - PullRequest
0 голосов
/ 01 декабря 2011

Я пишу функцию для класса 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 списками.

Edit2: Я предполагаю, что правильный код будет:

(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)))))))

1 Ответ

1 голос
/ 01 декабря 2011

Если вы хотите изменить слот объекта, вам нужно передать сам объект в свою функцию, а не только значение слота, который вы хотите изменить.

РЕДАКТИРОВАТЬ: относительно edit2 вопроса

Я предполагаю, 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 с исходным и пустым списком в качестве аргументов и присваивает результат слоту (он же переменная экземпляра).

...