Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

why cant an Int and a floating point number be added in haskell

Tags:

haskell

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?

like image 758
Rasmus Avatar asked Nov 28 '22 07:11

Rasmus


2 Answers

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.

like image 182
Ben Avatar answered Dec 05 '22 02:12

Ben


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

like image 42
Nicolas Avatar answered Dec 05 '22 02:12

Nicolas