As Rainer Joswig mentioned above, you should use the common lisp built-in function butlast
.
But, if you still want to see what an efficient recursive version would look like:
(defun butlast2 (list)
(labels ((butlast2-worker (list result)
(if (null list)
(nreverse result)
(let ((element (first list))
(rest (rest list)))
(if (null rest)
(nreverse result)
(butlast2-worker rest (cons element result)))))))
(butlast2-worker list ())))
As long as your lisp implementation supports tail call optimization, this will be converted into a loop. The trick is that whenever butlast2-worker
is called, its result will be returned directly, meaning that you don't need to keep track of the arguments/internal variables from previous calls of the function. Which lastly means that you don't need to keep filling the call stack as you would normally do for a recursive function.
Looking at Rainer Joswig's definition, you can see a tremendous difference in size. Behold the power of loop
, and learn to use it wisely whenever you can (or better: use iterate
http://common-lisp.net/project/iterate/).