借助累积参数转换可遍历结构

两个 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