Haskell monoid可折叠玫瑰树

时间:2014-10-08 12:52:02

标签: class haskell monoids

我需要为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。

4 个答案:

答案 0 :(得分:8)

fold的实施是正确的,没有理由改变它。

问题是fold不足以定义Foldable。来自the documentation

  

class Foldable t where Source

     

可以折叠的数据结构。

     

最小完整定义:foldMapfoldr

因此,您必须定义foldMapfoldr(或两者)。定义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))

否则将抛出关于函数折叠中非穷举模式的预期。