This was prompted by Resolving the type of `f = f (<*>) pure`, which discusses a more complicated example, but this one works too.
The following definition compiles without problem:
w :: Integral a => a
w = fromInteger w
...Of course it doesn't work runtime-wise, but that's beside the question. The point is that the definition of w
itself uses a specialised version of w :: Integer
. Clearly that is a suitable instantiation, and therefore typechecks.
However, if we remove the signature, then GHC infers not the above type, but only the concrete one:
w' = fromInteger w'
GHCi> :t w
w :: Integral a => a
GHCi> :t w'
w' :: Integer
Well, when I saw this, I was fairly sure this was the monomorphism restriction at work. It's well known that also e.g.
i = 3
GHCi> :t i
i :: Integer
although i :: Num p => p
would be perfectly possible. And indeed, i :: Num p => p
is inferred if -XNoMonomorphismRestriction
is active, i.e. if the monomorphism restriction is disabled.
However, in case of w'
only the type Integer
is inferred even when the monomorphism restriction is disabled.
To count out that this has something to do with defaulting:
fromFloat :: RealFrac a => Float -> a
q :: RealFrac a => a
q = fromFloat q
q' = fromFloat q'
GHCi> :t q
q :: RealFrac a => a
GHCi> :t q'
q' :: Float
Why is the polymorphic type not inferred?
Polymorphic recursion (where a function calls itself at a different type than the one at which it was called) always requires a type signature. The full explanation is in Section 4.4.1 of the Haskell 2010 Report:
If a variable
f
is defined without providing a corresponding type signature declaration, then each use off
outside its own declaration group (see Section 4.5) is treated as having the corresponding inferred, or principal type. However, to ensure that type inference is still possible, the defining occurrence, and all uses off
within its declaration group must have the same monomorphic type (from which the principal type is obtained by generalization, as described in Section 4.5.2).
The same section later presents an example of polymorphic recursion supported by a type signature.
My understanding is that unaided type inference is generally undecidable in the presence of polymorphic recursion, so Haskell doesn't even try.
In this case, the type checker starts with
w :: a
where a
is a meta-variable. Since fromInteger
is called with w
as an argument within its own declaration (and therefore within its declaration group), the type checker unifies a
with Integer
. There are no variables left to generalize.
A slight modification of your program gives a different result for the same reason:
v = fromIntegral v
By your original reasoning, Haskell would infer v :: forall a. Num a => a
, defaulting the v
on the RHS to type Integer
:
v :: forall a. Num a => a
v = fromIntegral (v :: Integer)
But instead, it starts with v :: a
. Since v
is passed to fromIntegral
, it imposes Integral a
. Finally, it generalizes a
. In the end, the program turns out to be
v :: forall a. Integral a => a
v = fromIntegral (v :: a)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With