(defun calculate-level-sums (lst)
  "Вычисляет суммы чисел на каждом уровне вложенности списка lst.
   Возвращает список пар (уровень сумма), отсортированный по уровню."
  (prepare-result (calculate-level-sums-helper lst 1 '())))

(defun calculate-level-sums-helper (lst level acc)
  "Рекурсивная функция, которая проходит по списку lst на заданном уровне level,
   накапливая суммы чисел в аккумуляторе acc. Аккумулятор acc - это список пар (уровень сумма)."
  (cond
    ((null lst) acc) ; Базовый случай: если список пуст, возвращаем аккумулятор
    (t (let ((head (car lst))  ; Берем первый элемент списка
             (tail (cdr lst))) ; Берем остаток списка
         (multiple-value-bind (new-acc remaining-tail)  ; Обрабатываем текущий элемент
           (process-item head level acc) ; Функция process-item определяет, что делать с элементом
           (calculate-level-sums-helper tail level new-acc)))))) ; Рекурсивно вызываем себя для остатка списка

(defun process-item (item level acc)
  "Обрабатывает один элемент item на заданном уровне level.
   Если элемент - число, обновляет аккумулятор.
   Если элемент - список, рекурсивно вызывает calculate-level-sums-helper для этого списка."
  (cond
    ((numberp item) ; Если элемент - число
     (values (update-level-sum acc level item) nil)) ; Обновляем сумму для уровня и возвращаем новый аккумулятор
    ((listp item) ; Если элемент - список
     (values (calculate-level-sums-helper item (1+ level) acc) nil)) ; Рекурсивно вызываем себя для списка, увеличив уровень
    (t (values acc nil)))) ; Если элемент - не число и не список (например, символ), просто игнорируем его

(defun update-level-sum (acc level value)
  "Обновляет аккумулятор acc суммой для заданного уровня level, добавляя value.
   Если уровень уже есть в аккумуляторе, добавляет value к существующей сумме.
   Иначе, добавляет новую пару (уровень value) в аккумулятор."
  (let ((existing (assoc level acc))) ; Ищем существующую запись для уровня
    (if existing ; Если уровень уже есть в аккумуляторе
        (let ((new-acc (remove existing acc :test #'equal))) ; Удаляем старую запись
          (cons (list level (+ value (cadr existing))) new-acc)) ; Добавляем обновленную запись с новой суммой
        (cons (list level value) acc)))) ; Иначе, добавляем новую пару (уровень value) в аккумулятор

(defun prepare-result (acc)
  "Подготавливает результат, сортируя аккумулятор по уровню и добавляя уровень 1 с суммой 0, если его нет."
  (if (assoc 1 acc) ; Проверяем, есть ли уровень 1 в аккумуляторе
      (sort acc #'< :key #'car) ; Если есть, сортируем аккумулятор по уровню
      (sort (cons '(1 0) acc) #'< :key #'car))) ; Иначе, добавляем (1 0) и сортируем

;; Тесты
(format t "~a~%" (calculate-level-sums '(a (b (4 (2 e (3) k 15) e 5) 7)))) ; ((1 0) (2 7) (3 9) (4 17) (5 3))
(format t "~a~%" (calculate-level-sums '(a b c))) ; ((1 0))
(format t "~a~%" (calculate-level-sums '(1 (2 (3))))) ; ((1 1) (2 2) (3 3))
(format t "~a~%" (calculate-level-sums'(1 (2 3 (4 (5 6)))))) ; ((1 1) (2 5) (3 4) (4 11))
