Why is there no Monoid for my Tree ?
It seems that there is no general way to “add” two Rose trees, because you would have trouble deciding what the root label of the sum tree is supposed to be. Hence you cannot have a general Monoid
instance for all possible sorts of Tree objects.
However, what's required here is simply an instance of Monoid
for type Tree ()
. There is only one possible value for the sum root label, so the problem disappears. The relevant code is easy to write:
{-# LANGUAGE FlexibleInstances #-}
import Data.Tree
instance Semigroup (Tree ()) where tr1 <> tr2 = Node () [tr1,tr2]
instance Monoid (Tree ()) where mempty = Node () []
And if that can help, you can have a Monoid
structure for any Tree m
type, assuming that the base type m
is itself a Monoid. Like this:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ExplicitForAll #-}
import Data.Tree
instance Monoid m => Semigroup (Tree m) where
tr1@(Node r1 f1) <> tr2@(Node r2 f2) = Node (r1<>r2) [tr1,tr2]
instance Monoid m => Monoid (Tree m) where
mempty = Node { rootLabel = (mempty::m), subForest = [] }
This code compiles flawlessly with GHC 8.6.5:
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ExplicitForAll #-}
import Data.Tree
import Control.Lens
import Control.Lens.Combinators
import Data.Tree.Lens
pathToLens :: (Applicative f) => (Int, [Int]) -> LensLike' f (Data.Tree.Forest a) (Data.Tree.Tree a)
pathToLens (rootIdx, branchIndices) =
ix rootIdx . helper branchIndices
where
helper :: (Applicative f) => [Int] -> LensLike' f (Data.Tree.Tree a) (Data.Tree.Tree a)
helper (idx : rest) = branches . ix idx . helper rest
helper [] = id
And the instance code above makes the error message about a missing Monoid
instance go away:
Testing under ghci
:
$ ghci
GHCi, version 8.6.5: http://www.haskell.org/ghc/ :? for help
Loaded GHCi configuration from /home/jeanpaul/.ghci
λ>
λ> :set -XScopedTypeVariables
λ> :set -XExplicitForAll
λ>
λ> :!cat pathToLens.hs
import Data.Tree
import Control.Lens
import Control.Lens.Combinators
import Data.Tree.Lens
pathToLens :: (Applicative f) => (Int, [Int]) -> LensLike' f (Data.Tree.Forest a) (Data.Tree.Tree a)
pathToLens (rootIdx, branchIndices) =
ix rootIdx . helper branchIndices
where
helper :: (Applicative f) => [Int] -> LensLike' f (Data.Tree.Tree a) (Data.Tree.Tree a)
helper (idx : rest) = branches . ix idx . helper rest
helper [] = id
λ>
λ> :load pathToLens.hs
[1 of 1] Compiling Main ( pathToLens.hs, interpreted )
Ok, one module loaded.
λ>
λ> ls = (pathToLens (0,[]))
λ> test = [Data.Tree.Node () []] ^. ls
<interactive>:10:36: error:
• No instance for (Monoid (Tree ())) arising from a use of ‘ls’
• In the second argument of ‘(^.)’, namely ‘ls’
In the expression: [Node () []] ^. ls
In an equation for ‘test’: test = [Node () []] ^. ls
λ>
So, at that stage, the initial problem is reproduced.
Now let's add our little monoid instance for (some) trees, and retry:
λ>
λ> instance Semigroup γ => Semigroup (Tree γ) where t1@(Node r1 f1) <> t2@(Node r2 f2) = Node (r1<>r2) [t1,t2]
λ>
λ> instance Monoid µ => Monoid (Tree µ) where mempty = Node { rootLabel = (mempty::µ), subForest = [] }
λ>
λ> test = [Data.Tree.Node () []] ^. ls
λ>
λ> :t test
test :: Tree ()
λ>
The Haskell Prelude provides a (trivial) Monoid
instance for ()
, and then the compiler infers from that the existence of another Monoid
instance for Tree ()
.