Haskell折叠函数在树上

时间:2017-03-26 16:37:16

标签: haskell

我正在努力解决这个问题:

  

编写折叠函数,将函数折叠在树上。 (因此,为   例如,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))

感谢您的任何建议

2 个答案:

答案 0 :(得分:4)

有一件事,在你的函数fold的签名中,你说它会收到2个参数,一个二元函数(可能是一个运算符),一个Tree并返回一个{ {1}}。现在,在定义中你有3个参数,a,一些f和一个v的构造函数。

解决方案可能就是这个:

Tree

您需要说明的是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.Foldable的文档。他们有一个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) 数据类型的示例。

答案 1 :(得分:3)

折叠可以在某种程度上机械地衍生自任何类型。这是foldMaybe

data Maybe a = Nothing | Just a

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

To" fold"数据类型意味着我们将提供一种方法,将该类型的每个可能的构造函数组合成最终类型r。这里,Maybe有两个构造函数:一个值为0,另一个值为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所采用的第二个值是(List a),那么为什么我们选择r?好!我们正在定义一个可以使用List a并返回r的函数,因此在与当前节点合并之前,我们将处理列表的其余部分。
  4. fold函数返回r
  5. 实现是什么样的?

    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
    

    同样,我们将TreeFork的所有递归用法替换为r类型参数。所以我们的全部功能如下:

    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?"
    

    我相信你可以填补这些漏洞:)