Вот одно из возможных решений в TXR Lisp:
(defun ascending-partitions (list)
(let ((indices (mappend (do if (>= @1 @2) (list @3))
list (cdr list) (range 1))))
(split list indices)))
Мы получаем числовые индексные позиции элементов в списке, которые не превышают их предшественников; затем мы используем функцию split
, чтобы разрезать список на части с этими индексами.
Расчет индексов осуществляется путем обработки трех списков с помощью функции mappend
: оригинала list
, параллельно с тем же списком с удаленным первым элементом (cdr list)
и бесконечным списком увеличивающихся целых чисел, начинающихся с 1, производимых (range 1)
.
Макрос do
пишет для нас анонимную функцию, в которой переменные @1
, @2
и @3
, встроенные в выражение, являются его тремя аргументами в указанном порядке. mappend
вызывать эту функцию с последовательными тройками значений, взятых из списков параллельно. Таким образом, @1
принимает значения из list
, @2
принимает последовательные значения из (cdr list)
, а @3
принимает последовательные значения из списка целых чисел. Всякий раз, когда @1
по меньшей мере равен его преемнику @2
, мы собираем позиционный индекс @3
в одноэлементный список. mappend
соединяет их вместе.
В отличие от этого, мы могли бы написать более прямое решение, которое требует больше кода, но лучше использует ресурсы машины:
(defun ascending-partitions (list)
(let (partition output prev)
(each ((item list)) ;; use (dolist (item list) in Common Lisp
(when (and prev (<= item prev))
(when partition
(push (nreverse partition) output)
(set partition nil))) ;; use setf or setq in Common Lisp
(push item partition)
(set prev item)) ;; ditto
(when partition
(push (nreverse partition) output))
(nreverse output)))