Search code examples
haskellpolymorphismtype-inferenceambiguity

Type mysteries. Why does this piece of code compile?


The code

default ()
h :: Bool
h = 1.0 == 1.0 --Error. Ambiguity.

does not compile. This is expected because there is ambiguity. It could be either Float or Double and Haskell doesn't know which one we want.

But the code

default ()
foo :: (Fractional a, Eq a) => a -> Bool
foo x = x == 1.0

compiles successfully. I don't fully understand why. Why isn't this also ambiguous?

I have the feeling that this is because whenever we call foo, we are guaranteed to have picked a concrete type in place of a, i.e., we are guaranteed to have fixed a to either Float or Double (or our custom type that has instances of both Fractional and Eq) at compile-time and therefore there is no ambiguity.

But this is just a feeling and I don't know if it's 100% accurate.


Solution

  • The definition for ambiguity in this context is given in Section 4.3.4 of Haskell Report:

    We say that an expression e has an ambiguous type if, in its type forall us. cx => t, there is a type variable u in us that occurs in cx but not in t. Such types are invalid.

    In foo :: (Fractional a, Eq a) => a -> Bool, there is no such variable (because a occurs in a -> Bool). In 1.0 == 1.0 the type is actually (Fractional a, Eq a) => Bool, so there is such a variable.

    The reason this kind of ambiguity is an error is because there is no way for compiler to choose between different instantiations of the variable a, and the result of the program can depend on which one it chooses. In this case 1.0 == 1.0 should always be True for any reasonable instantiation, but 1) the compiler doesn't know this; 2) not all instantiations are reasonable.