可穿越结构作为具有内容的形状
如果类型 t
是 Traversable
那么 t a
的值可以分成两部分:它们的形状和它们的内容:
data Traversed t a = Traversed { shape::t (), contents :: [a] }
其中内容与使用 Foldable
实例访问的内容相同。
朝着一个方向,从 t a
到 Traversed t a
除了 Functor
和 Foldable
之外不需要任何东西
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 . recombine
和 recombine . break
都是同一性。值得注意的是,这意味着在 contents
中有完全正确的数字元素来完全填充 shape
而没有剩余。
Traversed t
本身就是 Traversable
。traverse
的实现通过使用列表的 Traversable
实例访问元素然后将惰性形状重新附加到结果来工作。
instance Traversable (Traversed t) where
traverse f (Traversed s c) = fmap (Traversed s) (traverse f c)