Reputation: 33
I'm confused about why this works:
f :: Num a => a -> a
f x = x * 42
But this doesn't:
g :: Num a => a -> a
g x = x * 4.2
I had understood that Num
enclosed all types that implemented operators (+)
, (-)
, (*)
. So, if 42
is an Int
and 4.2
is a Fractional
, and both types implement the operator (*)
, why am I getting this error for g
?:
Could not deduce (Fractional a) arising from the literal ‘4.2’
from the context (Num a)
bound by the type signature for g :: Num a => a -> a
at file.hs:9:6-20
Possible fix:
add (Fractional a) to the context of
the type signature for g :: Num a => a -> a
Upvotes: 2
Views: 278
Reputation: 27023
Haskell types work differently than it appears you are expecting.
Num a => a -> a
does not mean "there is some type a
that is an instance of Num
for which this takes a value of type a
and returns a value of type a
."
It means "For every single type a
that is an instance of Num
, this takes a value of type a
and returns a value of type a
."
This means that it has to work for any type the caller chooses. If the caller chooses a ~ Int
(~
is the syntax for type equality, which some optional GHC features enable as a constraint) and then calls g 1
, what Int
value should that be?
Well, that doesn't work out very well. 4.2
isn't a valid Int
. So the *
operator fails to type-check, because it can't make the types of its arguments match.
This is why it has a more restrictive type - the types it accepts must be types that the literal 4.2
is a valid representation of. That ends up requiring a Fractional
constraint.
Type variables in Haskell are universally quantified. They always make statements about all types which satisfy their constraints. If there is ever a counter-example possible, things won't type-check.
Upvotes: 4
Reputation: 3276
The problem is that the Num a
constraint is too broad. Using the interpreter might help:
Prelude> :type 42
42 :: Num t => t
Prelude> :type 4.2
4.2 :: Fractional t => t
Numeric literals in Haskell are polymorphic, so as the types are saying, the literals are instantiated as any type as long as the type is a Num
or, respectively, a Fractional
.
Now look at the type signature of the (*)
function from the Num
class:
Prelude> :type (*)
(*) :: Num a => a -> a -> a
The (*)
operator works on any Num
value, but the two operands have the same type. So if you are multiplying by a value of Fractional type (whatever type the literal 4.2
will be instantiated into), the other operand must be Fractional as well, and the same type in particular. This is why the Num
constraint on your function is too broad: your function cannot work on any Num
type, but only on Fractional
s, hence the compiler is saying that you are missing a Fractional a =>
constraint in the type signature.
If you let the compiler inference the type of your function, it will agree:
Prelude> let g x = x * 4.2
Prelude> :type g
g :: Fractional a => a -> a
Upvotes: 5
Reputation: 15164
The numeric constant 42
is defined to be the same as fromIntegral (42::Integer)
, and any instance of Num
has an implementation of fromIntegral
. It occurs in the expression x * 42
, so its inferred type is the same as x
, which is an instance
of Num
. So the compiler calls the proper version of fromIntegral
for that Num
instance
(or rather, does the calculation at compile time) and everything is hunky-dorey.
But a constant with a decimal point tries to convert from a decimal to the type of x
. All we know about that type is that it’s an instance
of Num
, so it can’t do the conversion in the general case. There’s no way to represent 4.2
as, say, an Integer
.
As the error message says, the compiler can convert a decimal constant to any Fractional
type. So change the type constraint from Num
to Fractional
, and the decimal will work.
Upvotes: 2