Using Haskell's map function to calculate the sum of a list
Haskell
addm::[Int]->Int
addm (x:xs) = sum(x:xs)
I was able to achieve to get a sum of a list using sum
function but is it possible to get the sum of a list using map
function? Also what the use of map function?
You can't really use map
to sum up a list, because map treats each list element independently from the others. You can use map
for example to increment each value in a list like in
map (+1) [1,2,3,4] -- gives [2,3,4,5]
Another way to implement your addm would be to use foldl:
addm' = foldl (+) 0
Here it is, the supposedly impossible definition of sum
in terms of map
:
sum' xs = let { ys = 0 : map (\(a,b) -> a + b) (zip xs ys) } in last ys
this actually shows how scanl
can be implemented in terms of map
(and zip
and last
), the above being equivalent to foldl (+) 0 xs === last $ scanl (+) 0 xs
:
scanl' f z xs = let { ys = z : map (uncurry f) (zip ys xs) } in ys
I expect one can calculate many things with map
, arranging for all kinds of information flow through zip
.
edit: the above is just a zipWith
in disguise of course (and zipWith
is kind of a map2
):
sum' xs = let { ys = 0 : zipWith (+) ys xs } in last ys
This seems to suggest that scanl
is more versatile than foldl
.
It is not possible to use map
to reduce a list to its sum. That recursive pattern is a fold
.
sum :: [Int] -> Int
sum = foldr (+) 0
As an aside, note that you can define map
as a fold as well:
map :: (a -> b) -> ([a] -> [b])
map f = fold (\x xs -> f x : xs) []
This is because foldr
is the canonical recursive function on lists.
References: A tutorial on the universality and expressiveness of fold, Graham Hutton, J. Functional Programming 9 (4): 355–372, July 1999.
After some insights I have to add another answer: You can't get the sum of a list with map
, but you can get the sum with its monadic version mapM
. All you need to do is to use a Writer
monad (see LYAHFGG) over the Sum
monoid (see LYAHFGG).
I wrote a specialized version, which is probably easier to understand:
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
is just a wrapper around some type which also keeps a "running sum." We can make Adder
a monad, and here it does some work: When the operation >>=
(a.k.a. "bind") is executed, it returns the new result and the value of the running sum of that result plus the original running sum. The toAdder
function takes an Int and creates an Adder
that holds that argument both as wrapped value and as running sum (actually we're not interested in the value, but only in the sum part). Then in sum'
mapM
can do its magic: While it works similar to map
for the values embedded in the monad, it executes "monadic" functions like toAdder
, and chains these calls (it uses sequence
to do this). At this point, we get through the "backdoor" of our monad the interaction between list elements that the standard map
is missing.