Я собираюсь дать вам несколько советов, а не полное решение, поскольку это может звучать как домашнее задание.
Мне нравится разбивка шагов, которые вы предложили. Для первого шага (переход от списка чисел с нулевыми маркерами к списку списков) я предлагаю сделать явную рекурсию; попробуйте это для шаблона:
splits [] = {- ... -}
splits (0:xs) = {- ... -}
splits (x:xs) = {- ... -}
Вы также можете злоупотреблять groupBy
, если вы осторожны.
Для второго шага похоже, что вы почти на месте; последний шаг, который вам нужен, это взглянуть на функцию map :: (a -> b) -> ([a] -> [b])
, которая берет нормальную функцию и запускает ее для каждого элемента списка.
В качестве бонусного упражнения вы можете подумать о том, как вы можете сделать все это за один выстрел одним фолдом. Это возможно - и даже не слишком сложно, если вы проследите, какими должны быть типы различных аргументов для foldr
/ foldl
!
Дополнения после изменения вопроса:
Так как похоже, что вы разработали решение, теперь я чувствую себя комфортно, давая несколько спойлеров. =)
Я предложил две возможные реализации; один, который идет шаг за шагом, как вы предложили, и другой, который идет все сразу. Шаг за шагом это может выглядеть так:
splits [] = []
splits (0:xs) = [] : splits xs
splits (x:xs) = case splits xs of
[] -> [[x]]
(ys:yss) -> ((x:ys):yss)
groups' = map sum . splits
Или вот так:
splits' = groupBy (\x y -> y /= 0)
groups'' = map sum . splits'
Полная версия может выглядеть так:
accumulate 0 xs = 0:xs
accumulate n (x:xs) = (n+x):xs
groups''' = foldr accumulate [0]
Чтобы убедиться, что вы понимаете это, вот несколько упражнений, которые вы можете попробовать:
- Что
splits
и splits'
делают с [1,2,3,0,4,5]
? [1,2,0,3,4,0]
? [0]
? []
? Проверьте свои прогнозы в ghci.
- Прогнозируйте, что выводит каждая из четырех версий
groups
(включая вашу) для таких входных данных, как []
или [1,2,0,3,4,0]
, а затем проверяйте свой прогноз в ghci.
- Измените
groups'''
, чтобы продемонстрировать поведение одной из других реализаций.
- Измените
groups'''
, чтобы использовать foldl
вместо foldr
.