尝试使用给定的fold函数将一棵树展平为一个列表。
treeFold :: (b -> a -> b -> b) -> b -> Tree a -> b
treeFold _ b Leaf = b
treeFold f b (Node lt x rt) = f (treeFold f b lt) x (treeFold f b rt)
这是我到目前为止想要尝试的:
treeToList :: Tree a -> [a]
treeToList = treeFold (\xs x ys -> xs ++ x : ys) (\x -> [x])
由于某种原因,我无法完全理解如何进行此操作? 感觉有些关于Haskell的事情我还不太了解。任何帮助将不胜感激以及如何去解决它。 谢谢!
编辑:
我意识到我在这里使用的类型签名完全是荒谬的。根据我的想法,在treeFold的类型签名中,第二个参数(b)可能是一个列表,因为在这种情况下它以某种方式充当累加器。这将使第三个参数(树a)成为等式左侧参数的某种形式。函数中的两个参数必须是Node中的左子树和右子树。第三个参数只是Node的值。在该函数中,我需要按顺序将左树,右树和值以常规方式组合在一起,但是我尝试过的所有不同变体都存在一些问题
答案 0 :(得分:4)
treeFold
的类型是
treeFold :: (b -> a -> b -> b) -> b -> Tree a -> b
您要返回值列表[a]
。
因此,结果类型b
必须等于[a]
,为我们提供了专门的类型签名
treeFold :: ([a] -> a -> [a] -> [a]) -> [a] -> Tree a -> [a]
请注意,第二个参数的类型为[a]
。
您传递的是什么价值?
答案 1 :(得分:4)
类型必须适合:
treeFold :: ( b -> a -> b -> b ) -> b -> Tree a -> b
treeToList = treeFold (\xs x ys -> xs ++ (x : ys)) z
-------------------------------------------------------------------
b a b b a b b
--------
b
由于x
和ys
参与相同的:
,因此它们的类型必须兼容:
(:) :: a -> [a] -> [a]
x :: a
ys :: b
-------------------
b ~ [a]
因此我们有
treeFold :: ( [a] -> a -> [a] -> [a] ) -> [a] -> Tree a->[a]
treeToList = treeFold (\ xs x ys -> xs ++ (x : ys)) z
-------------------------------------------------------------------
[a] a [a] [a] a [a] [a]
--------
[a]
结论:最后一个参数z
必须具有类型[a]
。
此参数的含义是什么?与折叠一样,数据类型定义中的每个“变体”都有一个对应于fold函数的参数。
(丢失的)数据类型定义是:
data Tree a = Node (Tree a) a (Tree a) | Leaf
折叠的类型是
treeFold :: ( b -> a -> b -> b ) -> b -> Tree a -> b
对应于
的“ 递归结果保持类型”
data TreeF a r = NodeF r a r | LeafF
因此,z
是“将每个Leaf
转换为的值”。
最自然的选择就是[]
。实际上,这是唯一的选择,因为我们对a
(在[a]
中)的类型一无所知。