繁体   English   中英

树上的Haskell折叠功能

[英]Haskell fold function on tree

我正在努力与这个例子:

编写一个将函数折叠到树上的折叠函数。 (因此,例如, fold min t将在树中找到最小的元素。)

 fold :: (a -> a -> a) -> Tree -> a 

*这是我的剧本

data Tree = Leaf Int
          | Fork Tree Int Tree
     deriving Show


t0 = Leaf 0
t1 = Fork (Fork (Leaf 1) 2 (Leaf 3)) 4 (Fork (Leaf 5) 6 (Leaf 7))
t2 = Fork (Fork (Fork (Leaf 1) 2 (Leaf 3)) 4 (Leaf 5)) 6 (Leaf 7)

fold :: (a -> a -> a) -> Tree -> a
fold f v (Leaf n) = v
fold f v (Fork l n r) = f (Folk l) (fold f v (Fork r))

感谢您的任何建议

有一件事,在函数fold的签名中,您要说它将接收2个参数,一个二进制函数(可以是一个运算符),一个Tree并返回a 现在,在定义中,您有3个参数f ,一些vTree的构造函数。

解决方案可能是这样的:

fold :: (Int -> Int -> Int) -> Tree -> Int
fold f (Leaf n) = n
fold f (Fork l n r) = f n m
    where
        m = f (fold f l) (fold f r)

您需要说您正在返回一个Int因为您的Tree拥有Int

编辑

此外,您可以使用刚性类型变量来重新定义数据。

data Tree a = Leaf a
            | Fork (Tree a) a (Tree a)
     deriving Show


fold :: (a -> a -> a) -> Tree a -> a
fold f (Leaf n) = n
fold f (Fork l n r) = f n m
    where
        m = f (fold f l) (fold f r)

我建议您阅读Data.Foldable的文档。 他们有一个使用Tree数据类型的示例。

折痕可以机械地衍生自任何类型。 这是foldMaybe

data Maybe a = Nothing | Just a

foldMaybe :: r -> (a -> r) -> Maybe a -> r
foldMaybe _ k (Just a) = k a
foldMaybe d _ Nothing  = d

“折叠”数据类型意味着我们将提供一种将该类型的每种可能的构造函数组合为最终类型r 在这里, Maybe有两个构造函数:一个构造函数具有0个值,另一个构造函数具有单个a类型a值。 因此,要折叠它,我们需要为Nothing情况提供一个值,并提供一个将Just a转换为r

让我们看一下list ,看看foldr是如何从中派生的。

data List a = Nil | Cons a (List a)

           [1]   [2    3    4]             [4]
foldList :: r -> (a -> r -> r) -> List a -> r
  1. 这是替换列表中的Nil时要使用的值。
  2. 这是用于结合Cons情况的功能。 由于Cons的第一个值是a ,因此该函数必须取a
  3. Cons取的第二个值是a (List a) ,为什么我们取r 好! 我们正在定义一个可以使用List a并返回r ,因此我们将在与当前节点合并之前处理列表的其余部分。
  4. fold函数返回r

实现是什么样的?

foldList nil cons list = case list of
    Nil -> nil
    Cons a as -> cons a (foldList nil cons list)

因此,我们将所有构造函数替换为对应的“析构函数”,并在必要时重复进行。

对于树木:

data Tree = Leaf Int | Fork Tree Int Tree

我们有两个构造函数:一个构造函数使用一个Int ,另一个构造函数使用三个参数TreeIntTree

让我们来写类型签名!

treeFold :: LeafCase r -> ForkCase r -> r

嗯,但是我们必须定义LeafCase

type LeafCase r = Int -> r

由于Leaf使用单个Int作为参数,因此这就是该函数的类型。

type ForkCase r = r -> Int -> r -> r

同样,我们用r类型参数替换了ForkTree所有递归用法。 因此,我们的完整功能如下所示:

foldTree :: (Int -> r) -> (r -> Int -> r -> r) -> Tree -> r

实施可能会像这样开始:

foldTree leaf fork tree = case tree of
    Leaf i -> error "halp"
    Fork l i r -> error "complete me?"

我有信心您可以填补这些空缺:)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM