Вычисление суммарной суммы списка в Haskell

Напишите функцию, которая возвращает текущую сумму списка. например [1,2,3,5] - [1,3,6,11]. Я пишу эту функцию, ниже которой можно вернуть окончательную сумму всех значений из списка. Так как я могу отделить их по одному?

sumlist' xx=aux xx 0
    where aux [] a=a
          aux (x:xs) a=aux xs (a+x)

Ответ 1

Вы можете настроить свою функцию для создания списка, просто добавив a+x к результату на каждом шаге и используя пустой список в качестве базового варианта:

sumlist' xx = aux xx 0
    where aux [] a = []
          aux (x:xs) a = (a+x) : aux xs (a+x)

Однако более идиоматично Haskell выражать подобные вещи как складку или сканирование.

Ответ 2

Я думаю, вам нужна комбинация scanl1 и (+), поэтому что-то вроде

scanl1 (+) *your list here*

scanl1 применит данную функцию к списку и сообщит каждое промежуточное значение в возвращаемый список.

Как, чтобы записать это в псевдокоде,

scanl1 (+) [1,2,3]

выводит список вроде:

[1, 1 + 2, 1 + 2 + 3]

или, другими словами,

[1, 3, 6]

Learn You A Haskell содержит множество отличных примеров и описаний сканирований, складок и многих других лакомств Haskell.

Надеюсь, что это поможет.

Ответ 3

Хотя scanl1 явно является "каноническим" решением, все же поучительно видеть, как вы могли бы это сделать с помощью foldl:

sumList xs = tail.reverse $ foldl acc [0] xs where 
  acc (y:ys) x = (x+y):y:ys

Или pointfree:

sumList = tail.reverse.foldl acc [0] where 
  acc (y:ys) x = (x+y):y:ys

Вот уродливый подход грубой силы:

sumList xs = reverse $ acc $ reverse xs where
  acc [] = []
  acc (x:xs) = (x + sum xs) : acc xs

Существует милое (но не очень эффективное) решение с использованием inits:

sumList xs = tail $ map sum $ inits xs

Снова pointfree:

sumList = tail.map sum.inits

Ответ 4

В связи с другим вопросом, который я нашел таким образом:

rsum xs = map (\(a,b)->a+b) (zip (0:(rsum xs)) xs)

Я думаю, что это даже довольно эффективно.