Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In Haskell, what is the most common way to apply a function to every Nth element of a list?

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?

like image 661
Ramith Jayatilleka Avatar asked Sep 25 '14 13:09

Ramith Jayatilleka


People also ask

How do you get the first N elements of a list in Haskell?

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.

What does list do in Haskell?

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.

How does ++ work in Haskell?

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.


1 Answers

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.

like image 177
Rein Henrichs Avatar answered Sep 25 '22 04:09

Rein Henrichs