5

With this code

import Control.Monad
import Control.Applicative
import Control.Monad.State

class DefVal a where
  defVal :: a

instance (DefVal a) => Alternative (Either a) where
  empty = Left defVal
  (Left _) <|> x = x
  x        <|> _ = x

instance (DefVal a) => MonadPlus (Either a) where
  mzero = empty
  mplus = (<|>)

newtype ErrString = ErrString { toString :: String }
  deriving Show

instance DefVal ErrString where
  defVal = ErrString "Default Error String"

I'm getting errors:

Duplicate instance declarations:
  instance DefVal a => Alternative (Either a)
    -- Defined at main.hs:10:10
  instance Control.Monad.Trans.Error.Error e =>
           Alternative (Either e)
    -- Defined in ‘Control.Monad.Trans.Error’

Duplicate instance declarations:
  instance DefVal a => MonadPlus (Either a)
    -- Defined at main.hs:15:10
  instance Control.Monad.Trans.Error.Error e => MonadPlus (Either e)
    -- Defined in ‘Control.Monad.Trans.Error’

Error disappears if I remove Control.Monad.State which imports Control.Monad.Trans.Error.

How can I import Control.Monad.State hiding Control.Monad.Trans.Error or hiding Either instances of Alternative and MonadPlus from there?

I use GHC-7.10.2

  • 1
    AFAIK currently there is absolutely no way to refer to instances in import/export lists. You're out of luck. See: http://stackoverflow.com/questions/8728596/explicitly-import-instances – Bakuriu Aug 29 '15 at 13:51

1 Answers1

4

Haskell 2010 report, section 5.4 says:

Instance declarations cannot be explicitly named on import or export lists. All instances in scope within a module are always exported and any import brings all instances in from the imported module. Thus, an instance declaration is in scope if and only if a chain of import declarations leads to the module containing the instance declaration.

So it's dictated by the standard that you cannot do what you are trying to do.

The reason is that by allowing this it would be possible to create programs that mix different instances producing incorrect results.

See Explicitly import instances for example.

There are some extensions (e.g. GeneralizedNewtypeDeriving, see Breaking Data.Set integrity without GeneralizedNewtypeDeriving) that allow to mix instances even without instances in the export/import lists.

In fact GHC already doesn't adhere 100% to the standard on this and allows malformed programs. It doesn't globally check for instance declarations, but only that only one instance is in scope where it is needed. See this answer.


In your case you probably should use some newtype around Either to avoid mixing the instances:

newtype MyEither e a = MyEither {runMyEither :: Either e a}


instance (DefVal a) => Alternative (MyEither a) where
  empty = MyEither (Left defVal)
  (MyEither (Left _)) <|> x = x
  x                   <|> _ = x

instance (DefVal a) => MonadPlus (MyEither a) where
  mzero = empty
  mplus = (<|>)

Whoever wants a value x ::Either a b to act as x :: MyEither a b can simply do MyEither x and then use runMyEither on the result.

Community
  • 1
  • 1
Bakuriu
  • 98,325
  • 22
  • 197
  • 231
  • If instances are always imported, hiding modules (if it's possible) won't hide them. Thanks for `newtype` advice! –  Aug 29 '15 at 14:27