用折叠之类的东西计算树深度的最常用方法是什么?

时间:2015-01-04 19:55:20

标签: haskell tree fold

计算Data.Tree深度需要哪些最小(最一般)信息? Data.Foldable的实例是否足够?

我最初尝试fold Tree并试图找到与Monoid类似的正确Max。有些东西告诉我,因为Monoid(计算深度)需要是关联的,所以它可能不能用于表示需要了解结构的任何折叠(如1 + maxChildrenDepth),但我我不确定。

我想知道什么样的思维过程会让我在这种情况下得到正确的抽象。

2 个答案:

答案 0 :(得分:5)

我无法说出它是否是最小/最常见的信息量。但一个通用的解决方案是给定的结构

以下是使用recursion-schemes的示例代码。不幸的是,递归方案使用Foldable来表示catamorphisms,这使它有些混乱。

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

import qualified Data.Foldable as F
import Data.Functor.Foldable
import Data.Semigroup
import Data.Tree

depth :: (Foldable f, F.Foldable (Base f)) => f -> Int
depth = cata ((+ 1) . maybe 0 getMax . getOption
              . F.foldMap (Option . Just . Max))

-- Necessary instances for Tree:

data TreeF a t = NodeF { rootLabel' :: a, subForest :: [t] }

type instance Base (Tree a) = TreeF a

instance Functor (TreeF a) where
    fmap f (NodeF x ts) = NodeF x (map f ts)

instance F.Foldable (TreeF a) where
    foldMap f (NodeF _ ts) = F.foldMap f ts

instance Foldable (Tree a) where
    project (Node x ts) = NodeF x ts

答案 1 :(得分:2)

要回答第一个问题:Data.Foldable 不够来计算树的深度。 Foldable的最小完整定义是foldr,它始终具有以下语义:

foldr f z = Data.List.foldr f z . toList

换句话说,Foldable实例完全的特征在于它在输入的列表投影上的行为(即toList),这会抛弃深度树的信息。

验证这个想法的其他方法涉及Foldable依赖于必须关联的monoid实例或各种fold函数以某种特定顺序逐个查看元素的事实没有其他信息,这必然会抛出实际的树结构。 (必须有多个树具有相同相对顺序的相同元素集。)

我不确定树特别是的最小抽象是什么,但我认为你问题的核心实际上有点广泛:看看最低金额会很有趣需要信息来计算关于具有类似折叠函数的类型的任意事实。

要做到这一点,折叠中的实际辅助函数必须为每种数据结构采用不同类型的参数。这自然会导致我们 catamorphisms ,它们是不同数据类型的广义折叠。

您可以在不同的Stack Overflow问题上阅读有关这些广义弃儿的更多信息:What constitutes a fold for types other than list?(为了披露/自我宣传,我在那里写了一篇答案:P。)