可穿越结构作为具有内容的形状

如果类型 tTraversable 那么 t a 的值可以分成两部分:它们的形状和它们的内容

data Traversed t a = Traversed { shape::t (), contents :: [a] }

其中内容与使用 Foldable 实例访问的内容相同。

朝着一个方向,从 t aTraversed t a 除了 FunctorFoldable 之外不需要任何东西

break :: (Functor t, Foldable t) => t a -> Traversed t a 
break ta = Traversed (fmap (const ()) ta) (toList ta)

但回去使用 traverse 功能至关重要

import Control.Monad.State

-- invariant: state is non-empty
pop::State [a] a
pop = state $ \(a:as) -> (a, as)

recombine::Traversable t => Traversed t a -> t a
recombine (Traversed s c) = evalState (traverse (const pop) s) c

Traversable 法则要求 break . recombinerecombine . break 都是同一性。值得注意的是,这意味着在 contents 中有完全正确的数字元素来完全填充 shape 而没有剩余。

Traversed t 本身就是 Traversabletraverse 的实现通过使用列表的 Traversable 实例访问元素然后将惰性形状重新附加到结果来工作。

instance Traversable (Traversed t) where
    traverse f (Traversed s c) = fmap (Traversed s) (traverse f c)