`everyNth` applies a function f to every nth item in a list. If you want to double every other item in a list you can do

everyNth 2 (*2) aList

In order to accomplish this, it makes an infinite list of functions where every nth function is `f` (the user-supplied function) and the rest are `id`. (This function terminates when applied to finite lists becase zipWith stops when the shorter of it's arguments runs out). So:

everyNth 2 (*2) [1, 2, 3, 4]

is the same as

zipWith ($) [id, (*2), id, (*2)] [1, 2, 3, 4]

On Fri, Feb 6, 2015 at 12:52 PM, Roelof Wobben <r.wobben@home.nl> wrote:
Alex Hammel schreef op 6-2-2015 om 20:41:
This is mostly for my own recreation, feel free to ignore it.

Your solution is fine, but it lacks modularity. What if you discover that you don't actually want to double every other number but triple it? Or if the list of numbers is suddenly a list of words and you need to capitalize every other one? You don't want to have to write a new function from scratch. Let's make a function that applies any function to every other value:

everyOther :: (a -> a) -> [a] -> [a]
everyOther _ []       = []
everyOther _ [x]      = [x]
everyOther f (x:y:xs) = x : f y : everyOther f xs

doubleEveryOther :: [Int] -> [Int]
doubleEveryOther = everyOther (*2)

But hang on, what if the requirements change again and now we have to double every third value? Writing something like this is no fun:

everyThird :: (a -> a) -> [a] -> [a]
everyThird _ []         = []
everyThird _ [x]        = [x]
everyThird _ [x,y]      = [x,y]
everyThird f (x:y:z:xs) = x : y : f z : everyThird f xs

And the implementation of everyHundredAndFifth will obviously be ridiculous. Clearly what we need is an `everyNth` function which allows the programmer to specify which list elements the function is applied to.

One trick is to create a list of functions and use zipWith ($). ($) is just function application; so a list with `id` at every position except the nth will work:

λ zipWith ($) [id, (+1), id, (+1)] [1, 2, 3, 4]
[1,3,3,5]

We can use `cycle` to make an infinite list of functions and `replicate` to generate the padding of the function list:

everyNth :: Int -> (a -> a) -> [a] -> [a]
everyNth n f = zipWith ($) fs
  where
      fs = cycle $ replicate (n-1) id ++ [f] -- e.g. cycle [id, f] when n is 2


oke, Can you also explain what this function does exactly.

I see a variable n and f and I see cycle en replicate and  a n-1

What is I want to multiply the second item by 2.
That was the challenge I had now.

Roelof


_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://www.haskell.org/mailman/listinfo/beginners