假设我有这种Tree
类型:
{-# LANGUAGE DeriveFoldable, DeriveFunctor #-}
data Tree a = Leaf | Branch (Tree a) a (Tree a) deriving(Functor,Foldable)
instance Traversable Tree where -- equivalent to the one I could derive, but written out for clarity
traverse _ Leaf = pure Leaf
traverse f (Branch l x r) = Branch <$> traverse f l <*> f x <*> traverse f r
编写一个函数来计算特定类型内事物的最大深度很容易:
depth Leaf = 0
depth (Branch l _ r) = 1 + max (depth l) (depth r)
但是要计算任意Traversable
. 我已经知道这Functor
还不够,因为您无法通过 获得有关它们内部事物“位置”的信息fmap
,而且我也已经知道这Foldable
还不够,因为foldr
两者foldMap
都只提供尽可能多的信息列表的结构。Traversable
不过,可能是因为它比Functor
和更通用Foldable
。
但是,在做了一些实验之后,我认为Traversable
两者都没有办法。到目前为止,这是我的逻辑。考虑这两棵树:
fooTree = Branch (Branch Leaf () Leaf) () (Branch Leaf () Leaf)
barTree = Branch (Branch Leaf () (Branch Leaf () Leaf)) () Leaf
现在,traverse (\() -> thingy) fooTree
是:
Branch <$> (Branch <$> pure Leaf <*> thingy <*> pure Leaf) <*> thingy <*> (Branch <$> pure Leaf <*> thingy <*> pure Leaf)
在大量使用应用法则和一些简化之后,它变成:
(\x y z -> Branch (Branch Leaf x Leaf) y (Branch Leaf z Leaf)) <$> thingy <*> thingy <*> thingy
同样,traverse (\() -> thingy) barTree
是:
Branch <$> (Branch <$> pure Leaf <*> thingy <*> (Branch <$> pure Leaf <*> thingy <*> pure Leaf)) <*> thingy <*> pure Leaf
在大量使用应用法则和一些简化之后,它变成:
(\x y z -> Branch (Branch Leaf x (Branch Leaf y Leaf)) z Leaf) <$> thingy <*> thingy <*> thingy
现在看起来它们具有相同的“形状”(唯一的区别是开头的 lambda,甚至它们的类型都相同),但它们来自具有不同深度的树traverse (\() -> thingy) fooTree
。traverse (\() -> thingy) barTree
这使我相信不可能找到 的深度traverse
,但我不是 100% 确定它,我不知道如何严格解释它。
我说得对吗,这是不可能的?如果是这样,那么如何才能真正严格地解释这一点?如果没有,那么你将如何实现它?