I've been trying to see how Haskell copes with subtyping so I came up with the following snippet:
{-# LANGUAGE RankNTypes #-}
f1 :: () -> Int
f1 _ = 5
f2 :: () -> (forall a. Integral a => a)
f2 = f1
The line f2 = f1 fails with an unexpected error message:
Couldn't match type ‘a’ with ‘Int’
‘a’ is a rigid type variable bound by
the type signature for:
f2 :: forall a. Integral a => () -> a
It seems that the existential has been promoted to a universal, which of course is unintended.
My guess is that in implementation terms f2 needs to return a value and a corresponding dictionary, while f1 simply returns a value of type Int. However, from a logical perspective the contract of f2 is "a function from () to some unknown instance of Integral" and f1 satisfies it perfectly.
Should GHC do some implicit magic to make it work or am I missing something?