[英]Haskell - using foldl or foldr instead of pattern matching for updating a list with a new value at a given index
我已經實現了一個 function (,.=),它給出了一個列表和一個包含列表中索引和新值的元組,用給定索引處的新值更新給定列表。
(!!=) :: [a] -> (Int,a) -> [a]
(!!=) xs (0, a) = a : tail xs
(!!=) [] (i, a) = error "Index not in the list"
(!!=) (x:xs) (i, a) = x : xs !!= (i-1, a)
作為一個有折疊概念的初學者,我想知道是否有一種方法可以使用 foldl 或 foldr 來實現相同的結果?
提前非常感謝。
我會給你我認為更容易理解的foldl
版本,以及我能想到的最簡單/最直接的版本。
但請注意,您不應該使用foldl
(使用foldl'
: https://wiki.haskell.org/Foldr_Foldl_Foldl' ) - 也不應該像這樣使用++
(使用:
並在之后反轉);)
無論如何,這是一個想法:
(!!=) xs (i, a) = snd $ foldl
(\(j, ys) x -> (j+1, if j == i then ys ++ [a] else ys ++ [x]))
(0, [])
xs
snd
,因為我最后只想要這個)作為練習,您可以嘗試:
:
而不是++
和reverse
foldr
zipWith
並使用此( zipWith (...) [0..] xs
)而不是折疊(這類似於使用帶有索引的map foldl
和foldr
都不能有效地完成這項特定的工作(除非您在折疊列表時通過模式匹配來“欺騙”它),盡管foldr
可以做得不那么糟糕。 不,您真正需要的是一種不同的折疊方式,有時稱為para
:
para :: (a -> [a] -> b -> b) -> b -> [a] -> b
para _f n [] = n
para f n (a : as) = f a as (para f n as)
para
與foldr
非常相似。 它們中的每一個都采用組合 function 並且對於每個元素,傳遞該元素的組合 function 以及折疊列表的 rest 的結果。 但是para
增加了一些額外的東西:它還通過了列表的 rest。 因此,一旦您到達替換點,就無需重建列表的尾部。
但是......你如何從一開始就計算foldr
或para
? 這帶來了一個經典的技巧,有時稱為“高階棄牌”。 而不是para go stop xs
生成一個list ,它將生成一個function ,它將插入 position 作為參數。
(!!=) :: [a] -> (Int, a) -> [a]
xs0 !!= (i0, new) = para go stop xs0 i0
where
-- If the list is empty, then no matter what index
-- you seek, it's not there.
stop = \_ -> error "Index not in the list"
-- We produce a function that takes an index. If the
-- index is 0, we combine the new element with "the rest of the list".
-- Otherwise we apply the function we get from folding up the rest of
-- the list to the predecessor of the index, and tack on the current
-- element.
go x xs r = \i -> case i of
0 -> new : xs
_ -> x : r (i - 1)
請注意, para
很容易實現foldr
:
foldr c = para (\a _ b -> c a b)
可能不太明顯的是foldr
可以實現para
(非常低效的版本):
para f n = snd . foldr go ([], n)
where
go x ~(xs, r) = (x : xs, f x xs r)
以免您產生錯誤的想法並認為para
比foldr
“更好”,要知道當不需要它的額外功能時, foldr
更易於使用,並且通常會被編譯為更高效的代碼。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.