Reputation: 10941
So I typed this up
{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, FunctionalDependencies #-}
import Data.Monoid
class Monoid m => Mconcat m a | a -> m where
mcon :: m -> a
instance Monoid m => Mconcat m m where
mcon m = m
instance Mconcat m a => Mconcat m (m -> a) where
mcon m m' = mcon (m `mappend` m')
and I get
[1 of 1] Compiling Main ( pad.hs, interpreted )
pad.hs:8:10:
Functional dependencies conflict between instance declarations:
instance Monoid m => Mconcat m m -- Defined at pad.hs:8:10
instance Mconcat m a => Mconcat m (m -> a)
-- Defined at pad.hs:11:10
Failed, modules loaded: none.
The thing is though, m
and m->a
cannot be equal! Why is it giving me a conflict? (Also, any tips as to how to make a polyvariadic mconcat (in the style of the printf
library)?
Upvotes: 0
Views: 129
Reputation: 14578
You can make this compile and do what you want by changing the second instance declaration and adding UndecidableInstances
:
{-# LANGUAGE UndecidableInstances #-}
...
instance {-# OVERLAPS #-} (Mconcat m a, o ~ (m -> a)) => Mconcat m o where
or on earlier versions of GHC this should work (untested)
{-# LANGUAGE UndecidableInstances, OverlappingInstances #-}
...
instance (Mconcat m a, o ~ (m -> a)) => Mconcat m o where
This works because GHC only looks at the head of an instance to determine if it satisfies the coverage condition, but you can (almost) always achieve the same instance by making this transformation. It even handles polymorphic cases!
>:set +t
>mcon [1] [2] [34,34,2,53] [34,23,43]
[1,2,34,34,2,53,34,23,43]
it :: Num t => [t]
>mcon "a" "b" "c" "d" "e"
"abcde"
it :: [Char]
Upvotes: 3