實現對於列表中的一個函數映射到每個第n個元素的功能:可以mapEvery與foldr相似
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f = zipWith ($) (drop 1 . cycle . take n $ f : repeat id)
是否有可能與foldr
像普通map
來實現這一點?
編輯:在標題中,將'文件夾'更改爲'foldr'。自動更正...
實現對於列表中的一個函數映射到每個第n個元素的功能:可以mapEvery與foldr相似
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f = zipWith ($) (drop 1 . cycle . take n $ f : repeat id)
是否有可能與foldr
像普通map
來實現這一點?
編輯:在標題中,將'文件夾'更改爲'foldr'。自動更正...
這裏有一個解決方案
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f as = foldr go (const []) as 1 where
go a as m
| m == n = f a : as 1
| otherwise = a : as (m+1)
這將使用「foldl
爲foldr
」招自左沿爲你折列表右側傳狀態。本質上,如果我們將foldr
的類型讀作(a -> r -> r) -> r -> [a] -> r
,那麼我們將r
實例化爲Int -> [a]
,其中傳遞的整數是我們未調用函數而傳遞的當前元素數。
是的,它可以:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery n f xs
= foldr (\y ys -> g y : ys) []
$ zip [1..] xs
where
g (i, y) = if i `mod` n == 0 then f y else y
而且因爲它是possible to implement zip
in terms of foldr
,你可以得到更多的摺疊-Y,如果你真的想要的。這甚至適用於無限列表:
> take 20 $ mapEvery 5 (+1) $ repeat 1
[1,1,1,1,2,1,1,1,1,2,1,1,1,1,2,1,1,1,1,2]
這是它看起來像更foldr
和內聯g
:
mapEvery :: Int -> (a -> a) -> [a] -> [a]
mapEvery _ _ [] = []
mapEvery n f xs
= foldr (\(i, y) ys -> (if i `mod` n == 0 then f y else y) : ys) []
$ foldr step (const []) [1..] xs
where
step _ _ [] = []
step x zipsfn (y:ys) = (x, y) : zipsfn ys
現在,我會建議寫這樣說?絕對不。儘管您仍然可以編寫「可讀」代碼,但您仍然可以獲得這種混淆。但它確實證明了可以使用非常強大的foldr
來實現相對複雜的功能。
我不會期望如此,至少不會有單一的摺疊。 – 2014-10-08 16:38:00
嗯?這真的很有趣。你將如何用多個'foldr'來實現它? – 2014-10-08 16:42:50
...沒關係,不要認爲這也可以。使用'foldr',你只能計算你列表的_end_中有多少元素,而不是從一開始就有多少元素。 – 2014-10-08 16:45:02