藉助累積引數轉換可遍歷結構

兩個 mapAccum 函式結合了摺疊和對映的操作。

--                                                       A Traversable structure
--                                                                   |
--                                                     A seed value  |
--                                                             |     |
--                                                            |-|  |---|
mapAccumL, mapAccumR::Traversable t => (a -> b -> (a, c)) -> a -> t b -> (a, t c)
--                                      |------------------|              |--------|
--                                               |                            |
--                       A folding function which produces a new mapped       |
--                         element 'c' and a new accumulator value 'a'        |
--                                                                            |
--                                                            Final accumulator value
--                                                             and mapped structure

這些函式概括了 fmap,因為它們允許對映的值取決於摺疊中先前發生的事情。他們概括了 foldl / foldr,因為他們將結構對映到位並將其減少到一個值。

例如,tails 可以使用 mapAccumR 實現,其姐妹 inits 可以使用 mapAccumL 實現。

tails, inits :: [a] -> [[a]]
tails = uncurry (:) . mapAccumR (\xs x -> (x:xs, xs)) []
inits = uncurry snoc . mapAccumL (\xs x -> (x `snoc` xs, xs)) []
    where snoc x xs = xs ++ [x]

ghci> tails "abc"
["abc", "bc", "c", ""]
ghci> inits "abc"
["", "a", "ab", "abc"]

mapAccumL 是通過遍歷 State applicative functor 來實現的。

{-# LANGUAGE DeriveFunctor #-}

newtype State s a = State { runState::s -> (s, a) } deriving Functor
instance Applicative (State s) where
    pure x = State $ \s -> (s, x)
    State ff <*> State fx = State $ \s -> let (t, f) = ff s
                                              (u, x) = fx t
                                          in (u, f x)

mapAccumL f z t = runState (traverse (State . flip f) t) z

mapAccumR 通過反向執行 mapAccumL 來工作

mapAccumR f z = fmap getReverse . mapAccumL f z . Reverse