将函数应用于列表中的每个第二个元素

Nau*_*ika 6 haskell list

我想将一个函数应用于列表中的每个第二个元素:

> mapToEverySecond (*2) [1..10]
[1,4,3,8,5,12,7,16,9,20] 
Run Code Online (Sandbox Code Playgroud)

我写了以下函数:

mapToEverySecond :: (a -> a) -> [a] -> [a]
mapToEverySecond f l = map (\(i,x) -> if odd i then f x else x) $ zip [0..] l
Run Code Online (Sandbox Code Playgroud)

这有效,但我想知道是否有更惯用的方法来做这样的事情.

Mar*_*aTh 7

我没有写过很多Haskell,但这是我想到的第一件事:

func :: (a -> a) -> [a] -> [a]
func f [] = []
func f [x] = [x]
func f (x:s:xs) = x:(f s):(func f xs)
Run Code Online (Sandbox Code Playgroud)

这有点过分,因为你不仅需要处理空列表,还需要处理带有一个元素的列表.这也不能很好地扩展(如果你想要每三分之一,或者

人们可以这样做,因为@Landei指出并写道

func :: (a -> a) -> [a] -> [a]
func f (x:s:xs) = x:(f s):(func f xs)
func f xs = xs
Run Code Online (Sandbox Code Playgroud)

为了摆脱丑陋检查的两个[]和[x],但是,恕我直言,这使得它有点困难阅读(至少第一次).


utd*_*mir 7

mapToEverySecond = zipWith ($) (cycle [id, (*2)])
Run Code Online (Sandbox Code Playgroud)

是我能想到的最小的,在我看来也看起来很清晰。它也有点随着每n次缩放。

编辑:哦,人们已经在评论中建议了。我不想偷它,但我真的认为这就是答案。


Han*_*Lub 5

我将如何做到这一点:

mapOnlyOddNumbered f []      = []
mapOnlyOddNumbered f (x:xs)  = f x : mapOnlyEvenNumbered f xs

mapOnlyEvenNumbered f []     = []
mapOnlyEvenNumbered f (x:xs) = x : mapOnlyOddNumbered f xs
Run Code Online (Sandbox Code Playgroud)

这是否是"惯用的"是一个意见问题(如果它适合那里我会把它作为评论),但看到许多不同的方法可能是有用的.您的解决方案与我的解决方案或评论中的解决方案一样有效,并且更容易更改为说mapOnlyEvery13nd或mapOnlyPrimeNumbered