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?