Why is it that in ghci I can enter:
5.0 * (3 - 1) > 10.0
But if I try and create a function in a .hs file and load it in:
test :: Float -> Int -> Int -> Float test a b c = a * (b - c)
I am hit with an error? "Couldnt match expected type 'Float' against inferred type 'Int'? And how can I write a function that takes in one floating point and 2 integer arguments and performs the above operation on them?
I am using ghci v6.12.1 if that makes a difference...
The result of multiplying a float and an integer is always going to be a float.
The result of the multiplication of a float and an int is a float . Besides that, it will get promoted to double when passing to printf . You need a %a , %e , %f or %g format. The %d format is used to print int types.
Double is the double-precision floating point type, a good choice for real numbers in the vast majority of cases. (Haskell also has Float , the single-precision counterpart of Double , which is usually less attractive due to further loss of precision.)
1. Converting float to integer. The multiplication between float and string is not supported in python. But, to avoid the error from being thrown, we can try converting the given integer value to a string value.
Numeric literals (i.e. just typing a number in Haskell code) are not some fixed type. They are polymorphic. They need to be evaluated in some context that requires them to have a concrete type.
So the expression 5.0 * (3 - 1)
is not multiplying an Int
by a Float
. 5.0
has to be some Fractional
type, 3
and 1
are each some Num
type. 3 - 1
means that the 3 and the 1 both have to be the same Num
type, but we still don't (yet) have any more constraints about which particular one it is; the result of the subtraction is the same type.
The *
means both arguments have to be the same type, and the result will be the same type too. Since 5.0
is some Fractional
type, the (3 - 1)
must be too. We already knew that 3
, 1
, and (3 - 1)
had to be some Num
type but all Fractional
types are also Num
types, so this requirements are not in conflict.
The end result is that the whole expression 5.0 * (3 - 1)
is some type that is Fractional
, and the 5.0
, 3
, and 1
are all the same type. You can use the :t
command in GHCi to see this:
Prelude> :t 5.0 * (3 - 1) 5.0 * (3 - 1) :: Fractional a => a
But to actually evaluate that expression, we need to do so for some concrete type. If we were evaluating this and passing it to some function that required Float
, Double
, or some other particular Fractional
type then Haskell would pick that one. If we just evaluate the expression with no other context requiring it to be a particular type, Haskell has some defaulting rules to automatically choose one for you (if the defaulting rules don't apply it will instead give you a type error about ambiguous type variables).
Prelude> 5.0 * (3 - 1) 10.0 Prelude> :t it it :: Double
Above I've evaluated 5.0 * (3 - 1)
, then asked for the type of the magic it
variable which GHCi always binds to the last value it evaluated. This tells me that GHCi has defaulted my Fractional a => a
type to just Double
, in order to compute that the value of the expression was 10.0
. In doing that evaluation, it only ever multipled (and subtracted) Double
s, it never multiplied a Double
by an Int
.
Now, that's what's going on when you attempt to multiple numeric literals that look like they might be of different types. But your test
function isn't multiplying literals, it's multiplying variables of particular known types. In Haskell you can't multiply an Int
by a Float
because the *
operator has type Num a => a -> a -> a
- it takes two values of the same numeric type and gives you a result that is that type. You can multiply an Int
by an Int
to get an Int
, or a Float
by a Float
to get a Float
. You can't multiply an Int
by a Float
to get a ???
.
Other languages support this sort of operation only by implicitly inserting calls to conversion functions under some circumstances. Haskell never implicitly converts between types, but it has the conversion functions. You just need to call them explicitly if you want them to be called. This would do the trick:
test :: Float -> Int -> Int -> Float test a b c = a * fromIntegral (b - c)
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