Haskell Language Type Application Interaction with ambiguous types


Example

Say you're introducing a class of types that have a size in bytes.

class SizeOf a where
    sizeOf :: a -> Int

The problem is that the size should be constant for every value of that type. We don't actually want the sizeOf function to depend on a, but only on it's type.

Without type applications, the best solution we had was the Proxy type defined like this

data Proxy a = Proxy

The purpose of this type is to carry type information, but no value information. Then our class could look like this

class SizeOf a where
    sizeOf :: Proxy a -> Int

Now you might be wondering, why not drop the first argument altogether? The type of our function would then just be sizeOf :: Int or, to be more precise because it is a method of a class, sizeOf :: SizeOf a => Int or to be even more explicit sizeOf :: forall a. SizeOf a => Int.

The problem is type inference. If I write sizeOf somewhere, the inference algorithm only knows that I expect an Int. It has no idea what type I want to substitute for a. Because of this, the definition gets rejected by the compiler unless you have the {-# LANGUAGE AllowAmbiguousTypes #-} extension enabled. In that case the definition compiles,it just can't be used anywhere without an ambiguity error.

Luckily, the introduction of type applications saves the day! Now we can write sizeOf @Int, explicitly saying that a is Int. Type applications allow us to provide a type parameter, even if it doesn't appear in the actual parameters of the function!