После некоторого понимания я должен добавить еще один ответ: Вы не можете получить сумму списка с помощью map
, но вы можете получить сумму с помощью монадической версии mapM
. Все, что вам нужно сделать, это использовать Writer
монаду (см. LYAHFGG ) над моноидом Sum
(см. LYAHFGG ).
Я написал специализированную версию, которая, вероятно, легче понять:
data Adder a = Adder a Int
instance Monad Adder where
return x = Adder x 0
(Adder x s) >>= f = let Adder x' s' = f x
in Adder x' (s + s')
toAdder x = Adder x x
sum' xs = let Adder _ s = mapM toAdder xs in s
main = print $ sum' [1..100]
--5050
Adder
- это просто обертка вокруг некоторого типа, которая также сохраняет «промежуточную сумму». Мы можем сделать Adder
монадой, и здесь она выполняет определенную работу: когда выполняется операция >>=
(она же «связывание»), она возвращает новый результат и значение промежуточной суммы этого результата plus первоначальная сумма бега . Функция toAdder
принимает Int и создает Adder
, который содержит этот аргумент как в виде обернутого значения, так и в качестве текущей суммы (на самом деле нас интересует не значение, а только часть суммы). Затем в sum'
mapM
можно творить чудеса: хотя он работает аналогично map
для значений, встроенных в монаду, он выполняет «монадические» функции, такие как toAdder
и цепочки этих вызовов (для этого используется sequence
). На этом этапе через «черный ход» нашей монады мы получаем взаимодействие между элементами списка, которое отсутствует в стандарте map
.