макрос push, сохраняющий функцию, но не выходя из нее

У меня есть функция:

(defun multi-push (L P)
  (print (if L "T" "F"))
  (print P)
  (when L
    (multi-push (cdr L) (push (car L) P)))
  P)

который я сделал, чтобы попытаться поместить список в другой список (я знаю, что список ввода L перевернут. Это сделано по дизайну). Операторы печати имеют смысл, но когда я смотрю на переменную P, она не видоизменяется, как я ожидаю.

Пример вывода REPL:

CL-USER> bob
(3 3 3)
CL-USER> (multi-push (list 1 2) bob)

"T"
(3 3 3)
"T"
(1 3 3 3)
"F"
(2 1 3 3 3)
(1 3 3 3)
CL-USER> bob
(3 3 3)

Что я сделал не так? Я думал PUSH (согласно [http://clhs.lisp.se/Body/m_push.htm]) изменяет свой второй аргумент на месте. Я также пробовал варианты, в которых я POP L и PUSH на P перед вызовом multi-push на L и P снова.

следует отметить, что строка (1 3 3 3) является выходом функции multi-push. Это также смущает меня.


person Stegosaurus    schedule 05.01.2020    source источник
comment
Ваш multipush — это функция, но обратите внимание, что push — это макрос. Это по уважительной причине.   -  person Kaz    schedule 06.01.2020


Ответы (1)


То, что push деструктивно мутирует, является связыванием, а не списком. Более правильно то, что push изменяет, является «местом», которое

форма, подходящая для использования в качестве обобщенного справочника

где «обобщенная ссылка»

ссылка на место хранения объекта как на переменную.

Эти две цитаты взяты из глоссария CLHS: раздел, в котором говорится об этом, называется 5.1< /а>.

Особенно:

> (let* ((l1 '(1 2 3))
         (l2 l1))
    (push 0 l1)
    (values l1 l2))
(0 1 2 3)
(1 2 3)

Также обратите внимание, что это допустимый CL, поскольку он не деструктивно изменяет структуру списка в кавычках. push должен быть макросом, поскольку функция не может делать то, что она делает: вы не можете написать функцию f так, чтобы:

(пусть* ((a (список 1 2 3)) (b a)) (f a b) (не (eq a b)))

было бы правдой.

Вы можете думать о (push x y) как о расширении до чего-то вроде (setf y (cons x y)), за исключением того, что он будет правильно обрабатывать множественную оценку.

person Community    schedule 05.01.2020
comment
Чтобы быть более точным, PUSH — это макрос, который превращается в код для выполнения работы. Это не функция и не может быть записана как функция. - person Xach; 06.01.2020
comment
Похоже, вы пытаетесь отследить входные данные, полученные функцией при каждом вызове. Если это так, вы можете избавиться от операторов печати и вместо этого сделать (трассировать множественное нажатие). Когда вы закончите отладку, выполните (untrack multi-push) - person Leo; 06.01.2020
comment
@Xach: я уточнил это сейчас: извините, я должен был сказать это в исходном ответе. - person ; 06.01.2020