鉴于以下ITree
,来自Typeclassopedia:
data ITree a = Leaf (Int -> a) | Node [ITree a]
foldTree
的正确签名是什么 - 折叠整个树?
我的错误尝试是不编译:
foldTree :: (a -> [b] -> b) -> ITree a -> b
foldTree f (Leaf x) = f x []
foldTree f (Node xs) = f _ $ map (foldTree f) xs
然而,传递Leaf x
案例的空列表对我来说似乎很奇怪。
此外,在Node
的第二个模式匹配中,我不知道如何应用a
,因为我没有应用Node [ITree a]
{{1}} }。
答案 0 :(得分:2)
我正试图找出foldTree
签名背后的原因。
根据Foldable section of the Typeclassopedia,通用折叠操作具有以下签名之一:
class Foldable t where
fold :: Monoid m => t m -> m
foldMap :: Monoid m => (a -> m) -> t a -> m
foldr :: (a -> b -> b) -> b -> t a -> b
foldl :: (a -> b -> a) -> a -> t b -> a
foldr1 :: (a -> a -> a) -> t a -> a
foldl1 :: (a -> a -> a) -> t a -> a
它还说其他人可能来自fold
或foldMap
。
让我们试着找出foldMap
的{{1}}内容。
来自签名:
ITree a
很明显,创建foldMap :: Monoid m => (a -> m) -> ITree a -> m
foldMap f (Leaf x) = ???
的唯一方法是将合并函数m
应用于某些f
。但是从a
获取a
的唯一方法是将Leaf x
(这是一个函数)应用于某些x
,如下所示:
Int
这里我们选择在0处评估foldMap f (Leaf x) = f (x 0)
,但任何整数常量都可以。
对于x
案例,这似乎是唯一的可能性:
Node
也就是说,我们折叠了所有树,为我们提供了foldMap f (Node ts) = mconcat [ foldMap f t | t <- ts ]
值列表,然后使用m
将其缩减为单个mconcat
。
总而言之,m
定义所发生的一切是:
foldMap