As you can read from my previous blog I want to make VrrmDiffLists monoids.
However it would also make sense to make them lists. Lists already have a monoid instance (++) and (mempty), and you can’t currently give them a new one. So what to do?
You can newtype them, but then you are always wrapping and unwrapping the values to do things with them. Which is less than ideal. Strictly speaking the lists are still lists, and you should be able to do listy things with them.
With the Num wrappers like Sum and Product things aren’t too bad as Num is a typeclass and you can just instantiate it easily or automatically derive it. Lists aren’t currently typeclasses, and while they have been made you still can’t use the common list operators on them, or use them in places where people have defined their libraries to use lists.
So the other option is to rework monoids so I can keep lists as lists.
This is my current way forward. The monoid nature data class is supposed to indicate monoidness of a class (although it could quite easily be a type (a, a->a->a) and use snd and fst to get at the members of the tuple). A DMonoid is a way of typeclassing a new class so you can still use all the monoids stuff. Ideally we would go back and change such things as Writers/Foldables to use monoid natures instead of relying on dmonoids.
data MonoidOver a = MO { getMempty :: a, getMappend :: a->a->a }
class DMonoid a where
defaultMonoidOver :: MonoidOver a
instance (DMonoid a) => Monoid a where
mempty = getMempty defaultMonoidOver
mappend = getMappend defaultMonoidOver
dmconcat dm = foldr (getMappend dm) (getMempty dm)
This kinda works, but I tried to implement a monad instance of a derived Writer, and got stuck trying to get mempty.
So this isn’t an elegant solution worth investing time in. Do we need a change to the type system? I’m sure such things have been proposed before. I’ll sketch my idea and I’ll call it Aspects. Defined when you instantiate something using // or other symbol. So
instance (Num//Sum a) => Monoid a where
mappend = (+)
mempty = 0
or
instance Monoid [a]//Diff where
mappend = MergeDiffs
mempty = []
[a]//Diff would type check differently to [a], but functions are automatically polymorphic over both if they accept [a]. Also you need a default instance of the typeclass you want to aspect over. Converting between aspects seems like something ugly unless you perhaps require classes to have aspects to implement something similar to the toInteger. fromIntegral trick. Or more precisely deconstruct itself then reconstruct it.
I'll have a look how feasible this is to implement something like this somehow, but it seems likely I will just wrap/unwrap my strings for now. *
Thanks go out to #haskell quicksilver, dmwit and others that answer my questions.
Todo for next time
Read trace monoids, something useful if I want to represent execution of a system that can go multiple ways I think, which might be nice to get down...
* It turns out that you can do something like this by instantiating things in a module and then importing that seperately, qualified by how you import.