P05 (*) Reverse a list.


;; The naive recursive solution, O(n²):

(defun naive-recursive-reverse (list)
  (if (endp list)
      (append (naive-recursive-reverse (rest list))
              (cons (first list) '()))))

;; A tail-recursive solution (with accumulator):

(defun recursive-reverse (list)
  (labels ((rev (list acc)
     (if (endp list)
          (rev (rest list) (cons (first list) acc)))))
      (rev list '())))

;; An iterative solution:

(defun iterative-reverse-do (list)
  (let ((acc '()))
    (do ((current list (rest current)))
        ((endp current) acc)
      (setf acc (cons (first current) acc)))))

(defun iterative-reverse-loop (list)
     :with result = '()
     :for item :in list
     :do (push item result)
     :finally (return result)))

;; The smartass, Common Lisp solution:

(defun my-reverse (list)
  (reverse list))

;; (mapcar (lambda (fun) (mapcar fun '(() (a) (a b) (a b c))))
;;         (list (function iterative-reverse-do)
;;               (function iterative-reverse-loop)
;;               (function naive-recursive-reverse)
;;               (function recursive-reverse)
;;               (function my-reverse)))
;; --> ((NIL (A) (B A) (C B A))
;;      (NIL (A) (B A) (C B A))
;;      (NIL (A) (B A) (C B A))
;;      (NIL (A) (B A) (C B A))
;;      (NIL (A) (B A) (C B A)))

;; A tail-recursive solution for the reversing of the list in place.
;; Notice that cl:nreverse may be implemented without reusing the
;; input list, cl:nreverse may just call cl:reverse.

(defun my-nreverse (list)
  (labels ((list-reverse (reverse list)
             (if (null list)
                 (let ((rest  (cdr list)))
                   (setf (cdr list) reverse)
                   (list-reverse list rest)))))
    (list-reverse nil list)))

;; (let* ((list     (list 1 2 3 4))
;;        (reversed (my-nreverse list)))
;;   (values list reversed))
;; --> (1)
;;     (4 3 2 1)

;;;; THE END ;;;;