Как сказал Райнер Йосвиг, вы должны использовать общую встроенную функцию lisp butlast
.
Но, если вы все еще хотите увидеть, что эффективный рекурсивный вариант будет выглядеть следующим образом:
(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())))
Пока ваш лепет реализация поддерживает оптимизацию хвостового вызова, это будет конвертировано в петлю. Фокус в том, что всякий раз, когда вызывается butlast2-worker
, его результат будет возвращен напрямую, что означает, что вам не нужно отслеживать аргументы/внутренние переменные из предыдущих вызовов функции. Последнее означает, что вам не нужно заполнять стек вызовов, как обычно, для рекурсивной функции.
Глядя на определение Райнера Йосвига, вы можете увидеть огромную разницу в размере. Вот сила loop
, и научитесь использовать ее с умом, когда сможете (или лучше: используйте iterate
http://common-lisp.net/project/iterate/).
Большое спасибо за butlast, кстати, что проблема с Append? – Sergey
'APPEND' должен отсканировать весь список, а также скопировать все элементы. Если вы вызываете 'APPEND' несколько раз в цикле, вы получаете функцию, которая экспоненциально медленнее, когда вы добавляете больше элементов. –
@Elias Mårtenson: Append не копирует последний список. –