Confusing "Ambiguous occurrence" error message in the presence of qualified imports
Compiling this program:
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Bug where
import Control.Applicative (Alternative)
import qualified Data.Map as Map
import qualified Data.Set as Set
newtype Foo a = MkFoo [a] deriving (Functor, Applicative)
instance Alternative Foo where
empty = undefined
Yields the following error message (I've tried GHC 8.10 through 9.8):
$ ghc-9.8.1 Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:11:3: error: [GHC-87543]
Ambiguous occurrence ‘empty’.
It could refer to
either ‘Map.empty’,
imported qualified from ‘Data.Map’ at Bug.hs:5:1-32
(and originally defined in ‘Data.Map.Internal’),
or ‘Set.empty’,
imported qualified from ‘Data.Set’ at Bug.hs:6:1-32
(and originally defined in ‘Data.Set.Internal’).
|
11 | empty = undefined
| ^^^^^
This program is invalid, but not for the reasons stated in this error message. empty
isn't ambiguous at all. Rather, it's not in scope in the first place! The fix is to bring it into scope like so:
-import Control.Applicative (Alternative)
+import Control.Applicative (Alternative(empty))
The error message would have you believe that the problem is that GHC cannot pick between Map.empty
and Set.empty
. But this isn't the case at all, as the program would not be valid if you substituted either of these identifiers into the instance. For instance, if you wrote this:
instance Alternative Foo where
Map.empty = undefined
Then GHC would instead produce this error message:
$ ghc-9.8.1 Bug.hs
[1 of 1] Compiling Bug ( Bug.hs, Bug.o )
Bug.hs:11:3: error: [GHC-87543]
Ambiguous occurrence ‘Map.empty’.
It could refer to
either ‘Map.empty’,
imported qualified from ‘Data.Map’ at Bug.hs:5:1-32
(and originally defined in ‘Data.Map.Internal’),
or ‘Set.empty’,
imported qualified from ‘Data.Set’ at Bug.hs:6:1-32
(and originally defined in ‘Data.Set.Internal’).
|
11 | Map.empty = undefined
| ^^^^^^^^^
Bug.hs:11:3: error: [GHC-28329]
Qualified name in binding position: Map.empty
|
11 | Map.empty = undefined
| ^^^^^^^^^
It took several minutes of head-scratching to realize what the actual issue was. It would be nice if GHC could tell me the actual problem (empty
not being in scope) in the first place.