why wont this work :-
(length [1,2,3,4]) + 3.2
while this works:-
2+3.3
I understand that in the first case the result is an Int+Float but is that not the same in the second case too, or does Haskell automatically infer the type in the second case to be :- Num+Num whereas it does not do that in the first case?
Haskell never does implicit type conversion for you. +
only ever works on two numbers of the same type, and gives you that type as the result as well. Any other usage of +
is an error, as you saw with your (length [1,2,3,4]) + 3.2
example.
However, numeric literals are overloaded in Haskell. 2
could be any numeric type, and 3.3
could be any fractional type. So when Haskell sees the expression 2 + 3.3
it can try to find a type which is both "numeric" and "fractional", and treat both numbers as that type so that the addition will work.
Speaking more precisely, +
has the type Num a => a -> a -> a
. 2
on its own is of type Num a => a
and 3.3
on its own is of type Fractional a => a
. Putting those 3 types together, the in the expression 2 + 3.3
both numbers can be given the type Fractional a => a
, because all Fractional
types are also Num
types, and this then also satisfies the type of +
. (If you type this expression into GHCi the a
gets filled in as Double
, because GHC has to default the type to something in order to evaluate it)
In the expression (length [1,2,3,4]) + 3.2
, the 3.2
is still overloaded (and in isolation would have type Fractional a => a
). But length [1,2,3,4]
has type Int
. Since one side is a fixed concrete type, the only way to satisfy the type for +
would be to fill in the a
on the other type with Int
, but that violates the Fractional
constraint; there's no way for 3.2
to be an Int
. So this expression is not well-typed.
However, any Integral
type (of which Int
is one) can be converted to any Num
type by applying fromIntegral
(this is actually how the integer literals like 2
can be treated as any numeric type). So (fromIntegral $ length [1,2,3,4]) + 3.2
will work.
In the first case, as you mentioned, length [1,2,3,4]
is explicitly an Int
and can't be converted implicitly into a Float
or into any Fractional
instance. While in the second, there is no explicit typing, thus Haskell can infer that the good type is an instance of Fractional
. You can see how numeric literal are handled by the compiler in the corresponding section (§6.4.1) of the Haskell 2010 report.
A workaround: (fromIntegral $ length [1,2,3,4]) + 3.2
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