Прекрасный ответ @ ÓscarLópez отвечает на непосредственный вопрос OP, но есть и другие способы решения проблемы, которые, возможно, не совсем то, что ищет профессор OP.
Можно было бы map
через входной список вместе с диапазоном индексов в списке, используя drop
, чтобы уменьшить список для каждого apply
, который суммирует оставшийся список. Здесь _x
- это (игнорируемое) значение, взятое из входного списка с помощью map
, n
- количество элементов в drop
, а xs
- это входной список:
(define (subtotal-list xs)
(map (lambda (_x n)
(apply + (drop xs n)))
xs
(range (length xs))))
scratch.rkt> (subtotal-list '(3 2 1))
'(6 3 1)
scratch.rkt> (subtotal-list '())
'()
Между прочим, в Common Lisp есть хорошая идиома для такого рода вещей, которая работает аналогично с помощью макроса LOOP
. Здесь x
берет не элементы из списка xs
, а весь список, и на каждой итерации x
уменьшается с помощью cdr
(по умолчанию):
(defun subtotal-list-cl (xs)
(loop
:for x :on xs
:collect (apply #'+ x)))
SCRATCH> (subtotal-list-cl '(3 2 1))
(6 3 1)
SCRATCH> (subtotal-list-cl '())
NIL
Возвращаясь к текущему назначению, если требуется итеративная вспомогательная процедура и если разрешено apply
, то может быть определена более краткая версия хвостовой рекурсивной процедуры. Здесь, поскольку промежуточные результаты cons
выводятся на переднюю часть аккумулятора, аккумулятор должен быть перевернут в конце:
(define (subtotal-list-iter xs)
(subtotal-list-helper xs '()))
(define (subtotal-list-helper xs acc)
(if (null? xs) (reverse acc)
(subtotal-list-helper (rest xs)
(cons (apply + xs) acc))))
scratch.rkt> (subtotal-list-iter '(3 2 1))
'(6 3 1)
scratch.rkt> (subtotal-list-iter '())
'()