Это не сложно осуществить (игнорируя случаи сбоев). Клавиши должны использовать (setf cdr)
для повторного использования данной ячейки cons и не потерять ссылку на предыдущий cdr.
(defun nreverse2 (list)
(recurse reving ((list list) (rslt '()))
(if (not (consp list))
rslt
(let ((rest (cdr list)))
(setf (cdr list) rslt)
(reving rest list)))))
(defmacro recurse (name args &rest body)
`(labels ((,name ,(mapcar #'car args) ,@body))
(,name ,@(mapcar #'cadr args))))
[править] Как уже отмечалось в комментарии, чтобы сделать это действительно на месте (и без связи с consing):
(defun reverse-in-place (l)
(let ((result l))
(recurse reving ((l l) (r (reverse l))
(cond ((not (consp l)) result)
(else (setf (car l) (car r))
(reving (cdr l) (cdr r)))))))
> (defvar l '(1 2 3))
> (reverse-in-place l))
(3 2 1)
> l
(3 2 1)
Это перерабатывает ячейки cons (поэтому его соответствующим образом называют «nreverse2» (n для не-consing)), но он не отменяет список _in place_. Концы, которые являются главой исходного списка, не являются главой перевернутого списка. Например, '(let ((l (список 1 2 3))) (nreverse2 l) l)' производит '(1)'. –