37

How do I explicitly import typeclass instances? Also, how do I do this with a qualified import?

Currently, I'm doing

import Control.Monad.Error ()

to import the monad instance that I can use for (Either String). Previously, I used

import Control.Monad.Error

I'm not satisfied with either one, because the Monad instance is implicitly imported.

Chris Martin
  • 30,334
  • 10
  • 78
  • 137
Matt Fenwick
  • 48,199
  • 22
  • 128
  • 192

3 Answers3

54

The inability to control imports of instances is one of the trade-offs the Haskell typeclass system makes. Here's an example in a hypothetical Haskell dialect where you can:

Foo.hs:

module Foo where

data Foo = FooA | FooB deriving (Eq, Ord)

Bar.hs:

module Bar (myMap) where

import Data.Map (Map)
import qualified Data.Map as Map

import Foo

myMap :: Map Foo Int
myMap = Map.singleton FooA 42

Baz.hs:

module Baz where

import Data.Map (Map)
import qualified Data.Map as Map

import Foo hiding (instance Ord Foo)
import Bar (myMap)

instance Ord Foo where
  FooA > FooB = True
  FooB > FooA = False

ouch :: Map Foo Int
ouch = Map.insert FooB 42 myMap

Yikes! The set myMap was created with the proper instance Ord Foo, but it's being combined with a map created with a different, contradictory instance.

Being able to do this would violate Haskell's open world assumption. Unfortunately, I don't know of a good, centralised resource for learning about it. This section of RWH might be helpful (I searched for "haskell open world assumption").

Ben Millwood
  • 6,754
  • 24
  • 45
ehird
  • 40,602
  • 3
  • 180
  • 182
  • Maps, not Sets. Good example, +1. – Daniel Fischer Jan 04 '12 at 19:21
  • 3
    Meaning, that if want to go that path, you would have to make instances first class, so that a Map can carry it's Ord dictionary around? – Teresa Siegmantel May 24 '12 at 18:21
  • 1
    Note that you can do something very similar in current Haskell98 as well. See e.g. the first answer [here](http://stackoverflow.com/questions/12735274/breaking-data-set-integrity-without-generalizednewtypederiving/12744568#12744568). So while this would make it (much) easier to create things like `ouch`, it's already possible. – Erik Hesselink Jul 05 '13 at 14:33
  • 5
    Technically, you cannot write a program containing conflicting instances for the same type and class in Haskell 98, by language standard fiat. However, GHC does not always detect conflicting instances, so it accepts some programs which it should not according to the standard. – Reid Barton Jan 04 '15 at 16:36
  • The conflicting instances are in different modules - could that fact be used to generate something like a unification error during type inference? – atravers Dec 01 '21 at 01:25
7

You can't. Instances are always implicitly exported and hence you can't explicitly import them. By the way, Either e's Monad instance is nowadays in Control.Monad.Instances.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
4

Although the generally correct answer would be "no, you can't", I suggest this horrendous solution:

copy + paste

Take a look at the library source code for the desired module, and copy/paste the necessary data declarations, imports, and function definitions into your own code. Don't copy the instances you don't want.

Depending on the problem at hand, the ghc type system extensions OverlappingInstances or IncoherentInstances might be an alternate solution, though this probably won't solve any problems with the base libraries.

Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • 1
    I think Matt wanted rather to be able to say something like `import Foo (instance Bar Baz)` than `import Foo (Bar, hiding instance Baz)`. – Daniel Fischer Jan 04 '12 at 19:28
  • 1
    @DanielFischer - well, yes. In the absence of being able to do that, though, if you absolutely need to do such a thing, copy+paste is the only "plan B" solution I could think of. It might also be nice to add a comment such as `{-# ThisInstanceTrumps #-}` to force GHC to use your instance instead of whatever instance it might otherwise choose. – Dan Burton Jan 05 '12 at 00:44
  • 5
    Wow, this is truly a horrendous suggestion. The only thing you left out is using `unsafeCoerce` for interoperation between the originals and your copy/pasted definitions. – John L Dec 27 '12 at 09:01
  • 3
    A firm **-1** from me. Why? Because **copy-pasting code is bad practice**. Why? Because it allows some of the most [freakingly weird stuff](http://superuser.com/questions/792607/why-does-windows-think-that-my-wireless-keyboard-is-a-toaster) to happen. – ulidtko Feb 24 '15 at 13:25
  • The usual solution, not mentioned above is not to copy but to wrap the type X for which one needs control over the instances in a newtype (which is removed by the compiler). For example avoid a default instance for Show for type X, by writing newtype X = X Q.X deriving (Eq, Ord), where the package which exports X is imported qualified as Q. Then an instance Show X (the new X) can be defined and exported. The compiler will catch when X and Q.X is confused! – user855443 Feb 28 '18 at 18:45