我需要为Rose树数据结构创建一个可折叠的实例:
data Rose a = a :> [Rose a]
deriving (Eq, Show)
使用以下monoid和rose相关的类/实例:
instance Functor Rose where
fmap f (a :> bs) = (f a) :> (map (fmap f) bs)
class Monoid a where
mempty :: a
(<>) :: a -> a -> a
instance Monoid [a] where
mempty = []
(<>) = (++)
我尝试了什么:
instance Foldable Rose where
fold (a:>b) = a <> (foldMap fold b)
但是这不能正常工作,对于系统检查我得到错误:
*** Failed! Exception: 'Prelude.undefined':
[] :> []
但我不确定为什么它不起作用,任何人都可以帮助我吗?
提前致谢!
最诚挚的问候, Skyfe。
答案 0 :(得分:8)
您fold
的实施是正确的,没有理由改变它。
问题是fold
不足以定义Foldable
。来自the documentation:
class Foldable t where Source
可以折叠的数据结构。
最小完整定义:
foldMap
或foldr
。
因此,您必须定义foldMap
或foldr
(或两者)。定义foldMap
更容易,更自然(在许多情况下也更有效)。所以你应该写一些类似的东西:
import Data.Foldable
import Data.Monoid
data Rose a = a :> [Rose a]
deriving (Eq, Show)
instance Foldable Rose where
foldMap f (x :> xs) = f x <> foldMap (foldMap f) xs
答案 1 :(得分:5)
这只是切线相关,但是如果您发现Rose Trees与Control.Comonad.Cofree
中的Cofree []
相同,那么您可以获得Foldable
实例&#34;免费&# 34;来自[]
的可折叠实例,如此:
import Control.Comonad.Cofree
import Data.Foldable as F
type RoseTree = Cofree []
将其加载到GHCi中:
λ> let tree = 1 :< [1 :< [], 2 :< [], 3 :< []] :: RoseTree Int
λ> :t F.foldr (+) 0 tree
F.foldr (+) 0 tree :: Int
λ> F.foldr (+) 0 tree
7
你也可以派生Foldable
,或编写自己的实现(就像你已经完成的那样)。
答案 2 :(得分:3)
似乎我找到了自己问题的答案。
解决方案:
instance Foldable Rose where
fold (a:>b) = a <> (foldr (<>) mempty (map fold b))
首先要使用head元素追加列表中的每个元素(并对每个玫瑰树的绑定元素执行相同的操作),然后将列表与非调整元素mempty一起折叠。
答案 3 :(得分:0)
虽然OP说他/她找到了答案,但解决方案缺乏基本情况:
instance Foldable Rose where
fold (a:>[]) = a <> mempty
fold (a:>b) = a <> (foldr (<>) mempty (map fold b))
否则将抛出关于函数折叠中非穷举模式的预期。