(Background: Trying to learn Haskell, very new to functional programming. Typically used to Python.)
Suppose I have a list of 2-tuples, a histogram:
let h = [(1,2),(3,5),(4,6),(5,3),(6,7),(7,4),(8,6),(9,1)]
In imperative terms, I want to change the second term of each pair to be the sum of all the previous second pairs. In Python, the following (admittedly complex) list comprehension could do it:
[(p[0], sum( [p[1] for p in histogram[:i+1]] ))
for i, p in enumerate(histogram)]
assuming histogram
refers to a list of 2-tuples like h
above.
Here's what I have so far in Haskell:
zip [fst p | p <- h] (scanl1 (+) [snd k | k <- h])
This works, but I wonder:
In case it isn't clear, this is the expected output for the above:
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
In a general way, you can't. Each size of tuple is a distinct type, whereas lists of any length are a single type. Thus, there's no good way to write a function that takes a list and returns a tuple of the same length--it wouldn't have a well-defined return type.
First, we write a function that takes an element and a list and pairs that element with every list member. Then, to make all possible pairs from a given list, we can pair the head element with all the remaining elements in the list. We then remove the head element and repeat the above process of the remaining list.
You could use this function
accumulate = scanl1 step
where step (_,acc) (p1,p2) = (p1,acc+p2)
Here is the result on your sample data:
*Main> accumulate h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
If you're new to Haskell this might be a little too early, but lens offers a nice succinct way:
> scanl1Of (traverse . _2) (+) h
[(1,2),(3,7),(4,13),(5,16),(6,23),(7,27),(8,33),(9,34)]
You can easily accumulate only the first one by switching to _1
:
> scanl1Of (traverse . _1) (+) h
[(1,2),(4,5),(8,6),(13,3),(19,7),(26,4),(34,6),(43,1)]
Or accumulate all values as a sort of nested list:
> scanl1Of (traverse . both) (+) h
[(1,3),(6,11),(15,21),(26,29),(35,42),(49,53),(61,67),(76,77)]
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With