Haskell Ambiguous Occurrences -- how to avoid?
I do the following in GHCI:
:m + Data.Map
let map = fromList [(1, 2)]
lookup 1 map
GHCI knows that map is a (Map Integer Integer). So why does it claim an ambiguity between Prelude.lookup and Data.Map.lookup when the type is clear and can I avoid?
<interactive>:1:0:
Ambiguous occurrence `lookup'
It could refer to either `Prelude.lookup', imported from Prelude
or `Data.Map.lookup', imported from Data.Map
> :t map
map :: Map Integer Integer
> :t Prelude.lookup
Prelude.lookup :: (Eq a) => a -> [(a, b)] -> Maybe b
> :t Data.Map.lookup
Data.Map.lookup :: (Ord k) => k -> Map k a -> Maybe a
Solution 1:
The types are clearly different but Haskell doesn't allow ad-hoc overloading of names, so you can only choose one lookup
to be used without a prefix.
The typical solution is to import Data.Map
qualified:
> import qualified Data.Map as Map
Then you can say
> lookup 1 [(1,2), (3,4)]
Just 2
> Map.lookup 1 Map.empty
Nothing
Usually, Haskell libraries either avoid re-using names from the Prelude, or else re-use a whole bunch of them. Data.Map
is one of the second, and the authors expect you to import it qualified.
[Edit to include ephemient's comment]
If you want to use Data.Map.lookup
without the prefix, you have to hide Prelude.lookup
since it's implicitly imported otherwise:
import Prelude hiding (lookup)
import Data.Map (lookup)
This is a bit weird but might be useful if you use Data.Map.lookup
a whole bunch and your data structures are all maps, never alists.
Solution 2:
On a slightly more general note, this is something that confused me at first--so, let me reiterate and emphasize something Nathan Sanders said:
Haskell doesn't allow ad-hoc overloading of names
This is true by default, but seems surprisingly non-obvious at first. Haskell allows two styles of polymorphic functions:
- Parametric polymorphism, which allows a function to operate on arbitrary types in a structurally identical, abstract manner
- Ad-hoc polymorphism, which allows a function to operate on any of a defined set of types in a structurally distinct but, hopefully, semantically identical manner
Parametric polymorphism is the standard (and preferred given a choice) approach in Haskell and related languages; ad-hoc polymorphism is the standard in most other languages, going by names such as "function overloading", and is often implemented in practice by writing multiple functions with the same name.
Ad-hoc polymorphism is enabled in Haskell by type classes, which require the class to be defined with all of its associated ad-hoc polymorphic functions, and instances to be explicitly declared for the types used by overload resolution. Functions defined outside of an instance declaration are never ad-hoc polymorphic, even if their types are sufficiently distinct that a reference would be unambiguous.
So, when multiple non-type-class functions with identical names are defined in different modules, importing both modules unqualified will result in errors if you try to use either function. Combinations of of Data.List
, Data.Map
, and Data.Set
are particularly egregious in this regard, and because parts of Data.List
are exported by the Prelude, the standard practice is (as Nathan Sanders says) to always import the others qualified.