[英]Haskell fold function on tree
I'm struggling with this example: 我正在努力与这个例子:
Write a fold function that folds a function over a tree. 编写一个将函数折叠到树上的折叠函数。 (Thus, for example,
fold min t
would find the smallest element in tree.) (因此,例如,fold min t
将在树中找到最小的元素。)fold :: (a -> a -> a) -> Tree -> a
*That's my script *这是我的剧本
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))
Thanks for any advice 感谢您的任何建议
One thing, in the signature of your function fold
, you're saying that it'll receive 2 arguments, a binary function (could be an operator), a Tree and returns an a
. 有一件事,在函数fold
的签名中,您要说它将接收2个参数,一个二进制函数(可以是一个运算符),一个Tree并返回a
。 Now, in the defintion you have 3 arguments, f
, some v
and a constructor of Tree
. 现在,在定义中,您有3个参数f
,一些v
和Tree
的构造函数。
The solution could be this one: 解决方案可能是这样的:
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)
You need to say that you are returning a Int
because your Tree
holds Int
. 您需要说您正在返回一个Int
因为您的Tree
拥有Int
。
EDIT 编辑
Furthermore, you can redefine your data with a rigid type variable. 此外,您可以使用刚性类型变量来重新定义数据。
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)
I suggest you to read the documentation of Data.Foldable . 我建议您阅读Data.Foldable的文档。 They have an example with a Tree
data type. 他们有一个使用Tree
数据类型的示例。
Folds can be somewhat mechanically derived from any type. 折痕可以机械地衍生自任何类型。 Here's foldMaybe
: 这是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" a data type means that we are going to provide a way of combining each of the possible constructors for that type into a final type r
. “折叠”数据类型意味着我们将提供一种将该类型的每种可能的构造函数组合为最终类型r
。 Here, Maybe
has two constructors: one with 0 values, and one with a single value of type a
. 在这里, Maybe
有两个构造函数:一个构造函数具有0个值,另一个构造函数具有单个a
类型a
值。 So, to fold it, we need to provide a value for the Nothing
case, and a function to convert the Just a
into an r
. 因此,要折叠它,我们需要为Nothing
情况提供一个值,并提供一个将Just a
转换为r
。
Let's look at list
, and see how foldr
is derived from it. 让我们看一下list
,看看foldr
是如何从中派生的。
data List a = Nil | Cons a (List a)
[1] [2 3 4] [4]
foldList :: r -> (a -> r -> r) -> List a -> r
Nil
in the list. 这是替换列表中的Nil
时要使用的值。 Cons
case. 这是用于结合Cons
情况的功能。 Since Cons
has an a
as it's first value, the function must take an a
. 由于Cons
的第一个值是a
,因此该函数必须取a
。 Cons
takes is a (List a)
, so why are we taking an r
? Cons
取的第二个值是a (List a)
,为什么我们取r
? Well! 好! We're defining a function that can take a List a
and return an r
, so we'll process the rest of the list before combining with the current node. 我们正在定义一个可以使用List a
并返回r
,因此我们将在与当前节点合并之前处理列表的其余部分。 r
. fold函数返回r
。 What does the implementation look like? 实现是什么样的?
foldList nil cons list = case list of
Nil -> nil
Cons a as -> cons a (foldList nil cons list)
So we replace all of the constructors with their "destructor" counterparts, recursing where necessary. 因此,我们将所有构造函数替换为对应的“析构函数”,并在必要时重复进行。
For trees: 对于树木:
data Tree = Leaf Int | Fork Tree Int Tree
We have two constructors: one takes an Int
, and the other takes three parameters Tree
, Int
, and Tree
. 我们有两个构造函数:一个构造函数使用一个Int
,另一个构造函数使用三个参数Tree
, Int
和Tree
。
Let us write the type signature! 让我们来写类型签名!
treeFold :: LeafCase r -> ForkCase r -> r
Ah, but we have to define LeafCase
: 嗯,但是我们必须定义LeafCase
:
type LeafCase r = Int -> r
Since Leaf
takes a single Int as parameter, that's what the type of this function must be. 由于Leaf
使用单个Int作为参数,因此这就是该函数的类型。
type ForkCase r = r -> Int -> r -> r
Likewise, we replace all the recursive uses of Tree
in Fork
with the r
type parameter. 同样,我们用r
类型参数替换了Fork
中Tree
所有递归用法。 So our full function looks like: 因此,我们的完整功能如下所示:
foldTree :: (Int -> r) -> (r -> Int -> r -> r) -> Tree -> r
The implementation might start like: 实施可能会像这样开始:
foldTree leaf fork tree = case tree of
Leaf i -> error "halp"
Fork l i r -> error "complete me?"
and I feel confident that you can fill in those holes :) 我有信心您可以填补这些空缺:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.