Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Data.Tree.Tree not have a monoid instance?

Tags:

haskell

I realise that the answer may be that there are multiple valid such instances (as is the case for e.g. integers; sum, product, ...). Perhaps someone has a more satisfying answer than this?

As Joachim Breitner excellently explains in this answer How do you implement monoid interface for this tree in haskell? any applicative has a monoid instance:

mempty :: Applicative f => Monoid a => f a
mempty = pure mempty

mappend :: Applicative f => Monoid a => f a -> f a -> f a
mappend f g = mappend <$> f <*> g

So I was wondering why Data.Tree.Tree from containers does not have such an instance? Same argument could be used for any other monad without an accompanying monoid instance. It only seems natural to me that they should have such instances. Maybe this is not the case. I hope someone can enlighten me.

I suppose another reason could be that the instance I propose for trees is not "useful". This is as unsatisfying as the multiple valid instances argument in my opinion.

like image 734
fredefox Avatar asked Jan 01 '23 15:01

fredefox


2 Answers

I don't know why it isn't available. However, the instance you propose is available once and for all via the Ap newtype, which provides an instance (Applicative f, Monoid m) => Monoid (Ap f m). So if you need the instance you write, you can get it with this, even though it doesn't exist on the bare Tree type.

like image 93
Daniel Wagner Avatar answered Jan 10 '23 12:01

Daniel Wagner


There are multiple valid instances. Tree also supports a "zippy" Applicative with its corresponding Ap-based monoid:

instance Applicative Tree where
  pure a = let t = Node a (repeat t) in t
  liftA2 f (Node a as) (Node b bs) =
    Node (f a b) (zipWith (liftA2 f) as bs)

instance Semigroup a => Semigroup (Tree a) where
  Node a as <> Node b bs =
    Node (a <> b) (zipWith (<>) as bs)

instance Monoid a => Monoid (Tree a) where
  mempty = Node mempty (repeat mempty)

I have no idea what instance, if any, would actually be useful.


Just for fun, here's a slightly silly one that just lifts the constructor over underlying monoids:

instance Semigroup a => Semigroup (Tree a) where
  Node a as <> Node b bs = Node (a <> b) (as ++ bs)

instance Monoid a => Monoid (Tree a) where
  mempty = Node mempty []
like image 31
dfeuer Avatar answered Jan 10 '23 10:01

dfeuer