简体   繁体   English

Haskell monoid可折叠玫瑰树

[英]Haskell monoid foldable rose tree

I need to make a foldable instance for a Rose tree data structure: 我需要为Rose树数据结构创建一个可折叠的实例:

data Rose a = a :> [Rose a]
    deriving (Eq, Show)

With the following monoid and rose-related class/instances: 使用以下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 = []
    (<>)   = (++)

What I tried: 我尝试了什么:

instance Foldable Rose where
    fold (a:>b) =  a <> (foldMap fold b)

However this is not working properly, for the system check I get the error: 但是这不能正常工作,对于系统检查我得到错误:

*** Failed! Exception: 'Prelude.undefined': 
[] :> []

But I'm not sure why it doesn't work, could anyone help me out? 但我不确定为什么它不起作用,任何人都可以帮助我吗?

Thanks in advance! 提前致谢!

Best Regards, Skyfe. 最诚挚的问候,Skyfe。

Your implementation of fold was correct, there is no reason to change it. 你的fold实现是正确的,没有理由改变它。

The problem is that fold isn't sufficient to define Foldable . 问题是fold不足以定义Foldable From the documentation : 文档

class Foldable t where Source

Data structures that can be folded. 可以折叠的数据结构。

Minimal complete definition: foldMap or foldr . 最小完整定义: foldMapfoldr

So you must define either foldMap or foldr (or both). 因此,您必须定义foldMapfoldr (或两者)。 Defining foldMap is easier and more natural (and also more effective in many cases). 定义foldMap更容易,更自然(在许多情况下也更有效)。 So you should write something like: 所以你应该这样写:

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

This is only tangentially related, but if you realize that Rose Trees are the same as Cofree [] from Control.Comonad.Cofree , then you can get a Foldable instance "for free" from the foldable instance of [] like so: 这仅仅是切向相关的,但是如果你认识到玫瑰树是一样Cofree []Control.Comonad.Cofree ,那么你就可以得到一个Foldable的的可折叠实例的实例“免费” []像这样:

import Control.Comonad.Cofree
import Data.Foldable as F

type RoseTree = Cofree []

Load it up into GHCi: 加载到GHCi中:

λ> let tree = 1 :< [1 :< [], 2 :< [], 3 :< []] :: RoseTree Int
λ> :t F.foldr (+) 0 tree
F.foldr (+) 0 tree :: Int
λ> F.foldr (+) 0 tree
7

You can also just derive Foldable , or write your own implementation (like you've done). 您也可以只获得Foldable ,或编写自己的实现(就像您已经完成的那样)。

It seems like I found the answer to my own question. 好像我找到了自己问题的答案。

Solution: 解:

instance Foldable Rose where
    fold (a:>b) =  a <> (foldr (<>) mempty (map fold b))

Had to first append each of the elements in the list with the head element (and do the same for each of the bound elements to those rose trees), then fold the list together with an non-adjusting element mempty. 必须首先使用head元素追加列表中的每个元素(并对每个玫瑰树的绑定元素执行相同的操作),然后将列表与非调整元素mempty一起折叠。

Although OP says he/she has found the answer, the solution lacks the base case: 虽然OP说他/她找到了答案,但解决方案缺乏基本情况:

instance Foldable Rose where
    fold (a:>[]) = a <> mempty
    fold (a:>b) =  a <> (foldr (<>) mempty (map fold b))

Otherwise an expection about non-exhaustive patterns in function fold will be thrown. 否则,将抛出关于函数折叠中的非穷举模式的预期。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM