在Haskell中,将函数应用于列表的每个第N个元素的最常用方法是什么?

Ram*_*eka 6 haskell list repeat sieve-of-eratosthenes circular-list

它非常常见,我遇到了一些元素列表,xs并希望对每个第N个元素做一些事情.最简单的例子是Sieve或Erastothenes,你想要"敲掉"给定素数的每一个倍数.我可以这样做的两种方法是通过计数器变量传递显式递归; 或zipWith ($) (cycle (replicate (n-1) id ++ f)).那么哪种方式更好/更优雅/更常用,或者是否有一些mapEveryN :: (a -> a) -> Int -> [a] -> [a]我没有找到的库函数?

Rei*_*chs 2

正如您和 bheklilr 提到的,cycle提供了一种实现此目的的好方法。不过,你可以利用一点懒惰的优势:

mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f = zipWith ($) (drop 1 . cycle . take n $ f : repeat id)
Run Code Online (Sandbox Code Playgroud)

zipWith和的使用cycle似乎比结合这两个任务的手写递归函数更惯用(由更简单的行为组成的复杂行为)。

注意tail这里使该函数未定义,n = 0因此drop 1更好。

据我所知,没有用于此目的的库函数。

  • 对列表的每个第 0 个元素执行某些操作可能是无意义的,因此在这种情况下函数最好失败。如果它在特定上下文中确实有意义,那么您应该弄清楚 n=0 时的适当行为是什么,而不是以“安全”的名义以某种任意方式使函数总计。幸运的是,cycle [] 已经是一个错误,因此将 tail 更改为 drop 1 没有任何效果。 (2认同)