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:
Your test
function was more general, before you add a signature:
> let test a b c = a * (b - c)
> :t test
test :: Num a => a -> a -> a -> a
You could restrict it, but all types must be the same:
test :: Fractional a => a -> a -> a -> a -- some real types
test :: Integral a => a -> a -> a -> a -- all integer types
test :: Float -> Float -> Float -> Float
test :: Int -> Int -> Int -> Int
test :: Int -> Float -> Float -> Float --wrong
By the way, 2
isn't Int
and 0.2
isn't Float
, let ask gchi
:
> :t 2
2 :: Num a => a
> :t 0.2
0.2 :: Fractional a => a
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)
Try the following instead:
test :: Float -> Int -> Int -> Float
test a b c = a * fromIntegral (b - c)
Why does this work?
b
and c
are both Int
s the expression (b - c)
is also an Int
.(*)
is Num a => a -> a -> a
.a
is of type Float
Haskell updates the type signature of (a*)
to Float -> Float
.(b - c)
is an Int
and not a Float
Haskell would complain if you tried doing a * (b - c)
.fromIntegral
is (Integral a, Num b) => a -> b
.fromIntegral (b - c)
is Num b => b
.Float
is an instance of typeclass Num
you're allowed to do a * fromIntegral (b - c)
because the type signature of (*)
is Num a => a -> a -> a
.test
evaluates to Float
.Hope this helped.
You need to use fromIntegral
on the integers before multiplying by the floats.
http://www.haskell.org/haskellwiki/Converting_numbers
In GHCI, the numbers aren't assumed to be floats or ints until you use them. (e.g: at run time). That works out better for REPL-style development.
In the compiler proper, there isn't any automatic coercion. It it sees the multiplication assumes that the two values must belong to a type-class that supports multiplication. e.g: multiplying ints , or multiplying floats. As you didn't use any other explicitly typed functions, it assumed ints. That assumption then differs with your (optional) type signature.