【问题标题】:What is the most general way to compute the depth of a tree with something like a fold?用折叠之类的东西计算树的深度的最一般方法是什么?
【发布时间】:2015-03-02 09:50:17
【问题描述】:

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

我最初尝试 foldTree 并在试图找到类似于 Max 的正确 Monoid 时遇到了困难。有些东西告诉我,由于Monoid(计算深度)需要是关联的,它可能不能用于表达任何需要了解结构的折叠(如1 + maxChildrenDepth),但我不确定.

我想知道什么样的思维过程可以让我对这种情况做出正确的抽象。

【问题讨论】:

  • 定义“最少信息”的含义。对于任何“有深度的结构”,我认为树本身非常简单。
  • 我非常喜欢这个问题。也许一个相关的问题是:有没有像 Traversable 这样使用 both 折叠 FunctorAlternativeApplicative 结构的东西?
  • (我在想什么的更多细节:用明显的Functor 实例定义data Depth a = Depth Nat 并不难。Applicative 半群可能是(+,0)Alternative 一个(max,0)。)
  • 不幸的是,Data.Foldable 在这里不会为您做任何事情,除了提供(可能是无限的)上限。它太“一维”了。您可以使用 Data.Foldable 实例为 Tree 执行的任何操作,您只需使用 toList
  • 计算树的深度所需的最少信息是……树的深度。我知道这不是那么有用,但它显然是正确的。

标签: haskell tree fold


【解决方案1】:

我不能说这是否是最少/最一般的信息量。但是一个通用的解决方案是给定的结构

这里是使用recursion-schemes的示例代码。

{-# LANGUAGE TypeFamilies, FlexibleContexts #-}

import Data.Functor.Foldable
import Data.Semigroup
import Data.Tree

depth :: (Recursive f, Foldable (Base f)) => f -> Int
depth = cata ((+ 1) . maybe 0 getMax . getOption
              . 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 Foldable (TreeF a) where
    foldMap f (NodeF _ ts) = foldMap f ts

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

【讨论】:

  • 我不认为F.Foldable实例是守法的,因为它丢弃了所有rootLabels。
  • @BoydStephenSmithJr。那是一种误解。数据类型TreeF a t 包含两种东西:a 类型的根标签和t 类型的子森林。 F.Foldable (TreeF a) 实例迭代 t 类型的元素,即在子林上 - a 类型甚至超出了实例的范围。
  • 四年过去了,我仍然不明白答案。但是,是的,这看起来确实像我要求的......
【解决方案2】:

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

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

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

验证这个想法的其他方法包括Foldable 依赖于一个必须是关联的幺半群实例的事实,或者各种fold 函数以某种特定顺序逐个查看元素而没有其他信息的事实,这必然会抛出实际的树结构。 (必须有不止一棵树具有相同的相对顺序的相同元素集。)

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

为此,折叠中的实际帮助函数必须为每种数据结构采用不同类型的参数。这自然会导致我们catamorphisms,这是对不同数据类型的广义折叠。

您可以在另一个 Stack Overflow 问题上阅读有关这些通用折叠的更多信息:What constitutes a fold for types other than list?(为了披露/自我推销,我在那里写了一个答案:P。)

【讨论】:

    猜你喜欢
    • 2014-01-28
    • 2018-02-13
    • 1970-01-01
    • 2018-11-26
    • 1970-01-01
    • 1970-01-01
    • 2010-10-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多