Why does ghci list an equality type constraint in the type signature for this function matchInt
which I constructed via pattern matching:
$ ghci
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Prelude> :{
Prelude| matchInt 1 = 3
Prelude| matchInt _ = 4
Prelude| :}
Prelude> matchInt 1
3
Prelude> matchInt 22
4
Prelude> :t matchInt
matchInt :: (Eq a, Num a, Num p) => a -> p
In contrast, when using a simple data constructor, there is no equality type constraint.
$ ghci
GHCi, version 8.2.1: http://www.haskell.org/ghc/ :? for help
Prelude> data Z = Y Int
Prelude> :{
Prelude| matchDataInt (Y 1) = 3
Prelude| matchDataInt _ = 4
Prelude| :}
Prelude> matchDataInt (Y 1)
3
Prelude> matchDataInt (Y 22)
4
Prelude> :t matchDataInt
matchDataInt :: Num p => Z -> p
Indeed instances of Z can not be compared:
Prelude> Y 22 == Y 33
<interactive>:11:1: error:
• No instance for (Eq Z) arising from a use of ‘==’
• In the expression: Y 22 == Y 33
In an equation for ‘it’: it = Y 22 == Y 33
So again, why does the matchInt
function list equality as a type constraint but not the function matchDataInt
?
This question is related. However, if an equality test is needed for matchInt
then why isn't it needed for matchDataInt
? And here I come to my key point: don't both matchInt
and matchDataInt
have to test against 1 for the pattern matching to operate?
Syntactically matchInt
is built on a pattern match, but the patern match here is an illusion. 1
is not a data constructor. Numeric literals are overloaded. 1
is equivalent to fromInteger #1
where #1
is a non-overloaded litteral (not expressible in standard Haskell) of type Integer
. You cannot really pattern match against such things.
So the compiler lets you write what is syntactically a pattern match, but this notation really denotes a guard:
matchInt 1 = ... -- what is written
matchInt x | x == fromInteger #1 = ... -- what it really means
Since the type of matchInt
is not explicitly given, it's inferred. It's a function, so the type is some refinement of a->b
. The call to fromInteger
gives rise to the constraint Num a
, and the call to ==
gives rise to the constraint Eq a
, and that's all we can tell about a
.
If OTOH we give the function an explicit signature, say
matchInt :: Int->Int
then we don't need to infer the type, but only check if it satisfies the constraints. Since Int
satisfies both Eq Int
and Num Int
, everything is ok.
And this is what's going on in your second example. The type you match is known to be Int
, not because of an explicit type signature but because it is inferred from the Y Int
alternative of Z
. Here again Int
already has all the needed instances.