In a programming language that is purely functional (like Haskell) or where you are only using it in a functional way (eg clojure); suppose you have a list/seq/enumerable (of unknown size) of integers and you want to produce a new list/seq/enumerable that contains the differences between successive items, how would you do it?
What I did previously in C# was to fold over the list and keep a state object as the aggregating value which recorded the 'previous' item so that you could do a diff on it from the current item. The the result list also had to go into the state object (which is a problem for a list of unknown size)
What is the general approach for doing this kind of thing functionally?
In clojure, you can use the
map
function:This is how it can be done in Haskell without any standard functions, just recursion and pattern matching:
OK, here are two C# versions for those who are interested:
First, the bad version, or the one the previously imperative (in other words I) might try to write as functional programming is learnt:
Then a better version using the idioms expressed in other answers in this question:
I am not sure, but it might be true that in this version the source enumerable is iterated over twice.
In Haskell you would probably just use some higher order function like
zipWith
. So you could do something like this:Note how I handled the
[]
case separately--if you pass an empty list totail
you get a runtime error, and Haskellers really, really hate runtime errors. However, in my function, I'm guaranteed thels
is not empty, so usingtail
is safe. (For reference,tail
just returns everything except the first item of the list. It's the same ascdr
in Scheme.)This just takes the list and its tail and combine all of the items using the
(-)
function.Given a list
[1,2,3,4]
, this would go something like this:This is a common pattern: you can compute surprisingly many things by cleverly using standard higher-order functions. You are also not afraid of passing in a list and its own tail to a function--there is no mutation to mess you up and the compiler is often very clever about optimizing code like this.
Coincidentally, if you like list comprehensions and don't mind enabling the
ParallelListComp
extension, you could writezipWith (-) (tail ls) ls
like this:For another Clojure solution, try
Just to complement the idiomatic answers: it is possible in functional languages to process a list using a state object, just like you described. It is definitely discouraged in cases when simpler solutions exist, but possible.
The following example implements iteration by computing the new 'state' and passing it recursively to self.
The state is represented in in the previous (
prev
) value from the list, the diffs computed so far (acc
) and the rest of the list left to process (coll
).