michael rice nowgate at yahoo.com
Fri Apr 10 15:55:07 EDT 2009

```Yes, that is nice, and also useful for calculating moving averages.

Thanks.

Michael

Date: Friday, April 10, 2009, 12:04 PM

Joe Fredette <jfredett <at> gmail.com> writes:

> We can write your original function in another, cleaner way though, too,
> since zip will "zip" to the smaller of the two lengths, so you don't
> need to worry about doing the init and the tail, so `s` is really:
>
> s _ []  = []
> s _ [x] = [x]
> s f ls  = [f a b | (a,b) <- zip ls (tail ls)]
>
> but there is a function which does precisely what the third case does,
> called "zipWith" which takes a
> binary function and two lists and -- well -- does what that list
> comprehension does. In fact, it does
> what your whole function does... In fact, it _is_ your function,
> specialized a little, eg:
>
> yourZipWith f ls = zipWith f ls (tail ls)

A nice generalization of this that can be really useful is

movingWindow :: Int -> [a] -> [[a]]
movingWindow 1 xs = map (:[]) xs
movingWindow n xs = zipWith (:) xs . tail \$ movingWindow (n-1) xs

So for example,

> movingWindow 3 [1..10]
[[1,2,3],[2,3,4],[3,4,5],[4,5,6],[5,6,7],[6,7,8],[7,8,9],[8,9,10]]

Then you can write

diff :: (Num a) => [a] -> [a]
diff = map (\[x,y] -> y - x) . movingWindow 2

Hopefully the intermediate lists are optimized away, but I haven't done any
performance testing.

_______________________________________________