【发布时间】:2019-09-26 00:18:35
【问题描述】:
假设我有这个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
现在 traverse (\() -> thingy) fooTree 和 traverse (\() -> thingy) barTree 看起来它们具有相同的“形状”(唯一的区别是开头的 lambda,甚至它们的类型都相同),但它们来自具有不同的树深度。这让我相信不可能找到traverse 的深度,但我不是 100% 确定它,我不知道如何严谨地解释它。
我说这不可能吗?如果是这样,那么如何才能真正严格地解释这一点?如果没有,那你将如何实现它?
【问题讨论】:
-
不可能。考虑深度优先和广度优先顺序都给出了有效的 Traversable 实现。
-
另外,考虑你需要什么除了
Traversable,这至少是tree-traversals提供的一些,例如Control.Applicative.Phase。
标签: haskell depth traversable