user4035
user4035

Reputation: 23759

Hiding instance declaration from Prelude

I am playing with Monoids now and wanted to define my instances of <> and mempty for a list. I wrote this:

instance Semigroup [a] where
  (<>) = (++)

instance Monoid [a] where
  mempty = []

But got an error:

Duplicate instance declarations:
     instance Monoid [a] -- Defined at newtype.hs:25:10
     instance Monoid [a] -- Defined in ‘GHC.Base’

Probably, I need to add this at the beginning of file:

import Prelude hiding (???)

What should I write in place of "???"?

Upvotes: 3

Views: 677

Answers (1)

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 477824

The Haskell report 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.

It is thus not possible to exclude a certain instance. That being said, here it is not necessary at all to implement your Semigroup and Monoid for a list, since it is already defined. Indeed if, we inspect the source code, we see for Semigroup [src]:

-- | @since 4.9.0.0
instance Semigroup [a] where
        (<>) = (++)
        {-# INLINE (<>) #-}

        stimes = stimesList

and for Monoid [src]:

-- | @since 2.01
instance Monoid [a] where
        {-# INLINE mempty #-}
        mempty  = []
        {-# INLINE mconcat #-}
        mconcat xss = [x | xs <- xss, x <- xs]

So this is already implemented exactly the way you implemented this yourself.

It is usually considered an anti-pattern to implement an instance of a typeclass you did not implement yourself, on a data type you did not implement yourself. This is called an orphan instance [haskell-wiki]:

An orphan instance is a type class instance for class C and type T which is neither defined in the module where C is defined nor in the module where T is defined.

Usually one wraps a type into another data constructor (with newtype) to define different instances for that type for a typeclass.

Upvotes: 6

Related Questions