
Thanks, Conor. I like your reason of appealing to f structure over t
structure in (f t). And, yes I'd forgotten to mention that the monoid
instance I suggested is exactly the one that holds for the representation
(under the newtype).
Deriving works just fine here:
deriving instance Monoid (Cont r a)
Cheers, - Conal
On 9/9/07, Conor McBride
Hi Conal
Conal:
I'd like to see the following addition to Control.Monad.Cont in mtl:
instance Monoid r => Monoid (Cont r a) where mempty = Cont mempty m `mappend` m' = Cont (runCont m `mappend` runCont m')
Does newtype deriving work here?
Stefan:
(My 2 cents: Why not mempty = return mempty; mappend = liftM2 mappend ? Instances are best if unambiguous.)
Conal:
I sure don't know how to resolve these situations of more than one credible instance. I'm seeing more & more of them.
My usual rule of thumb is that inherent natural monoidal structure should have a higher priority than just applicative lifting of monoidal structure from the value type. Here it's a bit harder to call because it's a choice of two lifts, but I'd suggest that (Cont r) has natural monoidal structure if r is a monoid, and hence this should take precedence over the applicative lifting (which is what liftM2 does, but with too restrictive a type).
I guess my fairly feeble reason for this rule of thumb is that it fits with what one would expect for []. It may also be to do with the way I read types: when I see a type application (f t), I think of it as an f-like thing with t-like details, hence the natural properties of f are somehow the more significant. Moreover, preferring the f-specific thing is no big deal if you have a cheap and uniform way to get the other thing (eg, liftA2 or idiom brackets). The f-specific thing usually requires special consideration, hence benefits most from overloading.
So I'm with you on this one.
All the best
Conor