Christopher King
Christopher King

Reputation: 10941

Why I am getting a conflict?

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

Answers (1)

user2407038
user2407038

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

Related Questions