
Joe Fredette
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. Chad