Its very common where I come across some list of elements xs
and want to do something to do something with every Nth element. The simplest example would be the Sieve or Erastothenes, where you want to "knock out" every multiple of a given prime. The two ways I could do this would be explicit recursion passing along a counter variable; or zipWith ($) (cycle (replicate (n-1) id ++ f))
. So which way is better/more elegant/more commonly used, or is there some library function like mapEveryN :: (a -> a) -> Int -> [a] -> [a]
that I haven't found?
There is a function in Haskell that takes first n elements of user-supplied list, named take . The syntax is: function-name arg1 arg2 . So, take takes first 1000 elements from an infinite list of numbers from 0 to infinity.
In Haskell, lists are a homogenous data structure. It stores several elements of the same type. That means that we can have a list of integers or a list of characters but we can't have a list that has a few integers and then a few characters.
The ++ operator is the list concatenation operator which takes two lists as operands and "combines" them into a single list. So if you have the list [x] and the list [y] then you can concatenate them like this: [x]++[y] to get [x, y ]. Notice that : takes an element and a list while ++ takes two lists.
As you and bheklilr mention, cycle
provides a nice way to accomplish this. You can take advantage of laziness a bit though:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f = zipWith ($) (drop 1 . cycle . take n $ f : repeat id)
The use of zipWith
and cycle
seems more idiomatic (complex behavior composed from simpler behaviors) than a hand-written recursive function that combines both tasks.
Note: tail
here makes this function undefined for n = 0
so drop 1
is preferable.
There isn't a library function for this that I'm aware of.
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