一些背景:我在Haskell中有一个foldT函数(类似于foldr,但用于树),它的类型如下。
foldT :: (a -> b -> b -> b) -> b -> Tree a -> b
这个foldT只接受类型(a -〉B -〉b -〉b)作为输入函数。
我试图找到一种方法将我的树转换成列表,但无法找到一种方法使我的append函数采用(a -〉B -〉b -〉b)的形式。
以下是无效的,因为它不是正确的类型:
append x y z = append x:y:z
任何帮助都将不胜感激。
谢谢你,谢谢你
4条答案
按热度按时间pnwntuvh1#
因为你还没有发布它,我会假设你的树是...
...并且
foldT
的a -> b -> b -> b
参数以声明Node
构造函数的字段的相同顺序获取这些字段。我试图找到一种方法将我的树转换为列表
让我们从以下类型开始解决这个问题:
您希望将其扁平化为列表,因此函数的结果类型必须为
[a]
:这给我们提供了一个好主意,让我们知道如何继续:
具有:
现在,继续讨论参数.
z
,它将代替无值的Leaf
s被插入,因此它必须是[]
。至于f
,它必须将从左分支和右分支创建的子表与直接在Node
中的值结合起来。假设是按序遍历,我们有:或者,不提
t
:就是这样。需要注意的是,重复使用左嵌套的
(++)
(在本例中会发生,因为foldT
会递归地遍历分支)可能会非常低效。在您关心性能的情况下,值得考虑实现级联函数的替代方法,例如difference lists。附言:关于术语的一个注意事项。说一个函数“像foldr,但是用于树”是不明确的,因为有两种众所周知的函数类似于
foldr
。首先,你有Foldable
类的方法(参见Benjamin Hodgson's answer),无论你做什么,它们都会在折叠时将树扁平化为一个列表。例如您正在使用的foldT
,它们能够利用树结构。ruyhziif2#
GHC可以自动填充
Foldable
类的一个示例,其中包含了您要查找的toList
。由于
Node
构造函数的字段的顺序,treeToList
的此定义将执行预排序遍历。2vuwiymt3#
如果你想把树转换成一个列表,那么这个函数相对容易,所以基本上如果你有树结构,比如:
然后你必须从树中提取值,并将第一个值添加到一个空列表中,然后在列表(++)操作符的帮助下,递归地将相同的方法应用于树的其他分支,以将所有结果追加到一个列表中,即:
然后折叠它,首先:
函数签名缺少一个参数,下面让我们看看签名:a(第一个参数)-〉B(第二个)-〉b(第三个)-〉b(返回类型)该函数接受3个参数/参数,但您提供的签名只有1个b类型**(我猜是您的累加器),所以基本上这就是您要查找的函数签名:
现在我们可以处理这个签名了,接下来让我们来看看函数:
虽然我不认为我应该给你答案,你应该多练习一下递归数据结构,这样你就可以更好地理解如何遍历它们。
jjjwad0x4#
你每次开始的第一件事就是开始匹配模式:)在这一点上,它几乎是机械的!
假设您有:
让我们开始匹配模式吧!:)
第一个
Tree
构造函数是什么?是Leaf
!我们需要
b
类型的东西......我们只有一种方法可以得到它。通过使用z
:)因此,从机械Angular 来看,我们可以进入下一个可能的模式:
我们可以使用
t1
、x
和t2
,我们可以使用f
,它需要a
类型的东西......我们有x :: a
:)f
还有两个参数,类型为b
,那么你认为我们可以在那里放什么呢?我们可以放z
两次,但是这有点无聊。我们如何从t1
和t2
得到b
的?