Lis*_*one 2 tree haskell traversable
我有一个玫瑰树结构,我想为其编写一个Traversable实例。因此,我从以下内容开始:
data Tree a = Tree a [Tree a] deriving (Show)
instance Functor Tree where
fmap f (Tree x subs) = Tree (f x) (fmap (fmap f) subs)
Run Code Online (Sandbox Code Playgroud)
我做了深度优先的变体:
newtype Depth a = Depth (Tree a) deriving (Show)
depth :: Tree a -> [a]
depth (Tree x subs) = x : concatMap depth subs
instance Functor Depth where
fmap f (Depth t) = Depth $ fmap f t
instance Foldable Depth where
foldMap f (Depth t) = mconcat $ f <$> depth t
instance Traversable Depth where
traverse f (Depth t) = Depth <$> go t
where go (Tree x subs) = Tree <$> f x <*> traverse go subs
Run Code Online (Sandbox Code Playgroud)
然后,我尝试了广度优先的变体:
newtype Breadth a = Breadth (Tree a) deriving (Show)
breadth :: Tree a -> [a]
breadth tree = go [tree]
where
go [] = []
go (Tree x subs:q) = x : go (q <> subs)
instance Functor Breadth where
fmap f (Breadth t) = Breadth $ fmap f t
instance Foldable Breadth where
foldMap f (Breadth t) = mconcat $ f <$> breadth t
instance Traversable Breadth where
traverse f (Breadth t) = ???
Run Code Online (Sandbox Code Playgroud)
而且我意识到,此方法的广度和深度优先变体Traversable应相同。是这样吗 我不相信我实际上已经在任何地方阅读过了,但是遍历与元素的顺序无关吗?
如果是这样,这会有点奇怪,因为Traversable可以直接为实现Tree,这意味着Foldable需要为实现Tree,但是显然有多种方法Foldable可以实现。
Traversable必须同意Foldable。特别是,如果Monoid m的话Applicative (Const m),引起了一致性规律foldMap f = getConst . traverse (Const . f)。因此不可能对Breadth和Depth共享一个Traversable。要么有一个不同的实现Traversable Breadth与其一致Foldable,要么根本没有。我可以制定一个我认为确实可以实现的实现,但是我还没有验证其他法律。
instance Traversable Breadth where
traverse f (Breadth t) = Breadth <$> head <$> go [t]
where
go [] = pure []
go ts = zipWith Tree <$> traverse f rs
<*> (fmap (rebuild css) $ go $ concat css)
where
(rs, css) = unzip $ map (\(Tree r cs) -> (r, cs)) ts
-- rebuild s d = evalState (traverse (state splitAt') d) s
-- I think, but let's keep the dependencies down, shall we?
rebuild [] [] = []
rebuild (struct : structs) destruct
= let (cs, destruct') = splitAt' struct destruct
in cs : rebuild structs destruct'
-- ignoring the as in a [a] makes it look like a number
splitAt' [] xs = ([], xs)
splitAt' (_ : n) (x : xs)
= let (pre, suf) = splitAt' n xs
in (x : pre, suf)
Run Code Online (Sandbox Code Playgroud)
这是多毛的,到处都是非总计,但应该可以解决。