Это не ответ, но он слишком длинный для комментария. Как предполагает Виллем Ван Онсем, ваш Monoid
экземпляр не является законным. Я подозреваю, что вы, вероятно, хотите одну из двух вещей:
Свободная магма
Свободная магма над типом может быть определена
data Magma a = Branch (Magma a) (Magma a) | Leaf a | Empty
deriving Show
Это, естественно, не моноид, но иногда полезно притвориться это одно:
instance Monoid (Magma a) where
mempty = Empty
mappend = Branch
-- For recent GHC, add this instance
instance Semigroup (Magma a) where
(<>) = Branch
Это можно использовать со сгибом, чтобы лучше понять структуру этого сгиба. Чтобы понять, как это работает, сравните результаты применения foldMap Leaf
к [1..20]
, Data.Sequence.fromList [1..20]
и Data.Set.fromList [1..20]
.
A (конкретная) свободная монада
Подумайте об обобщении вашего дерева, чтобы разрешить разные типы во внутренних узлах, чем в листьях:
data Tree a b = Node a (Tree a b) (Tree a b) | Leaf b
deriving (Show, Eq)
(Получается, что это свободная монада над функтором Tree a
, определенная
data TreeF a b = NodeF a b b
но нам не нужно вдаваться в подробности того, что это значит.)
Операция монады для монады Tree a
является своего рода «прививкой», когда листья заменяются деревьями.
instance Functor (Tree a) where
fmap f (Leaf b) = Leaf (f b)
fmap f (Node a l r) = Node a (fmap f l) (fmap f r)
instance Applicative (Tree a) where
pure = Leaf
(<*>) = ap
liftA2 = liftM2
instance Monad (Tree a) where
Leaf b >>= f = f b
Node a l r >>= f = Node a (l >>= f) (r >>= f)
Вы можете думать, что >>=
поддерживает своего рода вертикальное добавление, когда дерево растет вниз от своих листьев.