Why the result of (/) function may also be Integral? - haskell

Consider:
> :t (/)
(/) :: Fractional a => a -> a -> a
and
> :t (round 10 / 100)
(round 10 / 100) :: (Fractional a, Integral a) => a
How could (/) result in Integral?

I believe you are misreading the result type
result :: (Fractional a, Integral a) => a
This type is a "contract" between the user of result and the implementor of result. Let's take it apart:
The user must first choose a type a
The user must then prove that the chosen a belongs to classes Fractional and Integral. Roughly, this means that the user has to provide a definition for the methods of such classes.
Finally, the implementor will provide a value of type a.
Part 2 is the crucial step. As we can see, the type of result does not promise to construct some value whose type is both a fractional and an integral. Quite the opposite: it requires that whoever wants to use that result value has to find such a type.
Concretely, this means that result is unusable. GHC does not raise a type error because it has no deep knowledge about the intended meaning of the type classes. Indeed, from a purely theoretical point of view, one could define a custom type and provide fractional/integral instances, e.g.
data A = A0 | A1 | A2
instance Num A where
...
instance Fractional A where
...
instance Integral A where
...
with some weird implementation, such as performing fractional operations modulo 3, but not integral operations.
Anyway, since something like A could be defined, GHC can not reject the type above.

Related

Why can a Num act like a Fractional?

As expected, this works fine:
foo :: Fractional a => a
foo = undefined -- datum
bar :: Num a => a -> a
bar a = undefined -- function
baz :: Fractional a => a
baz = bar foo -- application
This works as expected because every Fractional is also a Num.
So as expected, we can pass a Fractional argument into a Num parameter.
On the other hand, the following works too. I don't understand why.
foo :: Fractional a => a -> a
foo a = undefined -- function
bar :: Num a => a
bar = undefined -- datum
baz :: Fractional a => a
baz = foo bar -- application
Works unexpectedly! There are Nums that are not Fractionals.
So why can I pass a Num argument into a Fractional parameter? Can you explain?
chi's answer gives a great high-level explanation of what's happening. I thought it might also be fun to give a slightly more low-level (but also more mechanical) way to understand this, so that you might be able to approach other similar problems, turn a crank, and get the right answer. I'm going to talk about types as a sort of protocol between the user of the value of that type and the implementer.
For forall a. t, the caller gets to choose a type, then they continue with protocol t (where a has been replaced with the caller's choice everywhere in t).
For Foo a => t, the caller must provide proof to the implementer that a is an instance of Foo. Then they continue with protocol t.
For t1 -> t2, the caller gets to choose a value of type t1 (e.g. by running protocol t1 with the roles of implementer and caller switched). Then they continue with protocol t2.
For any type t (that is, at any time), the implementer can cut the protocol short by just producing a value of the appropriate type. If none of the rules above apply (e.g. if we have reached a base type like Int or a bare type variable like a), the implementer must do so.
Now let's give some distinct names to your terms so we can differentiate them:
valFrac :: forall a. Fractional a => a
valNum :: forall a. Num a => a
idFrac :: forall a. Fractional a => a -> a
idNum :: forall a. Num a => a -> a
We also have two definitions we want to explore:
applyIdNum :: forall a. Fractional a => a
applyIdNum = idNum valFrac
applyIdFrac :: forall a. Fractional a => a
applyIdFrac = idFrac valNum
Let's talk about applyIdNum first. The protocol says:
Caller chooses a type a.
Caller proves it is Fractional.
Implementer provides a value of type a.
The implementation says:
Implementer starts the idNum protocol as the caller. So, she must:
Choose a type a. She quietly makes the same choice as her caller did.
Prove that a is an instance of Num. This is no problem, because she actually knows that a is Fractional, and this implies Num.
Provide a value of type a. Here she chooses valFrac. To be complete, she must then show that valFrac has the type a.
So the implementer now runs the valFrac protocol. She:
Chooses a type a. Here she quietly chooses the type that idNum is expecting, which happens to coincidentally be the same as the type that her caller chose for a.
Prove that a is an instance of Fractional. She uses the same proof her caller did.
The implementer of valFrac then promises to provide a value of type a, as needed.
For completeness, here is the analogous discussion for applyIdFrac. The protocol says:
Caller chooses a type a.
Caller proves that a is Fractional.
Implementer must provide a value of type a.
The implementation says:
Implementer will execute the idFrac protocol. So, she must:
Choose a type. Here she quietly chooses whatever her caller chose.
Prove that a is Fractional. She passes on her caller's proof of this.
Choose a value of type a. She will execute the valNum protocol to do this; and we must check that this produces a value of type a.
During the execution of the valNum protocol, she:
Chooses a type. Here she chooses the type that idFrac expects, namely a; this also happens to be the type her caller chose.
Prove that Num a holds. This she can do, because her caller supplied a proof that Fractional a, and you can extract a proof of Num a from a proof of Fractional a.
The implementer of valNum then provides a value of type a, as needed.
With all the details on the field, we can now try to zoom out and see the big picture. Both applyIdNum and applyIdFrac have the same type, namely forall a. Fractional a => a. So the implementer in both cases gets to assume that a is an instance of Fractional. But since all Fractional instances are Num instances, this means the implementer gets to assume both Fractional and Num apply. This makes it easy to use functions or values that assume either constraint in the implementation.
P.S. I repeatedly used the adverb "quietly" for choices of types needed during the forall a. t protocol. This is because Haskell tries very hard to hide these choices from the user. But you can make them explicit if you like with the TypeApplications extension; choosing type t in protocol f uses the syntax f #t. Instance proofs are still silently managed on your behalf, though.
The type a in baz :: Fractional a => a is chosen by whoever calls baz. It is their responsibility to guarantee that their choice of a type is in the Fractional class. Since Fractional is a subclass of Num, the type a must therefore be also a Num. Hence, baz can use both foo and bar.
In other words, because of the subclass relation, the signature
baz :: Fractional a => a
is essentially equivalent to
baz :: (Fractional a, Num a) => a
Your second example is actually of the same kind as the first one, it does not matter which one between foo, bar is the function and which one is the argument. You might also consider this:
foo :: Fractional a => a
foo = undefined
bar :: Num a => a
bar = undefined
baz :: Fractional a => a
baz = foo + bar -- Works
Works as expected because every Fractional is also a Num.
That is correct, but it's important to be precise about what this means. It means this: every type in the Fractional class is also in the Num class. It does not mean what someone with an OO or dynamic background might understand: “every value in a Num type is also in a Fractional type”. If this were the case, then your reasoning would make sense: then the Num value bar would be insufficiently general to be used in the foo function. ...or actually it wouldn't be, because in an OO language the number hierarchy would work in the other direction – other languages usually allow you to cast any numerical value to a fractional one, but the other direction would in these languages incur round, which reasonably strongly typed ones won't automatically do!
In Haskell, you need to worry about none of this, because there are never any implicit type conversions. bar and foo work on the exact same type, that this type happens a variable a is secondary. Now, both bar and foo constrain this single type in different ways, but because it's the same type that's constrained you simply get a combination (Num a, Fractional a) of both constraints, which due to Num a => Fractional a is equivalent to Fractional a alone.
TL;DR: it is not the case that Num a => a is a Num value, but rather it is a definition that can be a value of any type of Num, whatever that type is, specifically, as determined by each specific place where it is used.
We define it first, and we use it, later.
And if we've defined it generally, so that it can be used at many different specific types, we can use it later at many different use sites, which will each demand a specific type of value to be provided for it by our definition. As long as that specific type conforms to the type constraints as per the definition and the use site.
That's what being a polymorphic definition is all about.
It is not a polymorphic value. That is a concept from the dynamic world, but ours is a static one. The types in Haskell are not decided at run time. They are known upfront.
Here's what happens:
> numfunc :: Num a => a -> a; numfunc = undefined
> fraval :: Fractional a => a; fraval = undefined
> :t numfunc fraval
numfunc fraval :: Fractional a => a
numfunc demands its argument to be in Num. fraval is a polymorphic definition, able to provide a datum of any type which is in Fractional as might be demanded of it by a particular use. Whatever it will be, since it's in Fractional, it's guaranteed to also be in Num, so it is acceptable by numfunc.
Since we now know that a is in Fractional (because of fraval), the type of the whole application is now known to be in Fractional as well (because of the type of numfunc).
Technically,
fraval :: Fractional a => a -- can provide any Fractional
numfunc :: Num a => a -> a -- is able to process a Num
-------------------------------------------------
numfunc fraval :: (Num a, Fractional a) => a -- can provide a Fractional
And (Num a, Fractional a) is simplified to the intersection of the type classes, i.e. just Fractional a.
This of course means that if there's nothing else in the rest of the code somewhere, further specifying the types, we'll get an ambiguous type error (unless some type defaulting kicks in). But there might be. For now this is acceptable, and has a type -- a polymorphic type, meaning, something else will have to further specify it somewhere in the rest of the code, at any particular use site where it appears. So for now, as a general polymorphic definition, this is perfectly acceptable.
Next,
> frafunc :: Fractional a => a -> a; frafunc = undefined
> numval :: Num a => a; numval = undefined
> :t frafunc numval
frafunc numval :: Fractional a => a
frafunc demands its type to be in Fractional. numval is able to provide a datum of whatever type is demanded of it as long as that type is in Num. So it's perfectly happy to oblige any demand for a Fractional type of value. Of course something else in the code will have to further specialize the types, but whatever. For now it's all good.
Technically,
numval :: Num a => a -- can provide any Num
frafunc :: Fractional a => a -> a -- is able to process a Fractional
-------------------------------------------------
frafunc numval :: (Num a, Fractional a) => a -- can provide any Fractional
(I post this answer because I think the simplest things can be a stumbling block for beginners, and these simplest things can be taken for granted without even noticing, by the experts. As the saying goes, we don't know who discovered water, but it sure wasn't a fish.)

How can a instance with Num type class coercion to Fractional implicitly?

I tested the numeric coercion by using GHCI:
>> let c = 1 :: Integer
>> 1 / 2
0.5
>> c / 2
<interactive>:15:1: error:
• No instance for (Fractional Integer) arising from a use of ‘/’
• In the expression: c / 2
In an equation for ‘it’: it = c / 2
>> :t (/)
(/) :: Fractional a => a -> a -> a -- (/) needs Fractional type
>> (fromInteger c) / 2
0.5
>>:t fromInteger
fromInteger :: Num a => Integer -> a -- Just convert the Integer to Num not to Fractional
I can use fromInteger function to convert a Integer type to Num (fromInteger has the type fromInteger :: Num a => Integer -> a), but I cannot understand that how can the type Num be converted to Fractional implicitly?
I know that if an instance has type Fractional it must have type Num (class Num a => Fractional a where), but does it necessary that if an instance has type Num it can be used as an instance with Fractional type?
#mnoronha Thanks for your detailed reply. There is only one question confuse me. I know the reason that type a cannot be used in function (/) is that type a is with type Integer which is not an instance of type class Fractional (the function (/) requires that the type of arguments must be instance of Fractional). What I don't understand is that even by calling fromInteger to convert the type integer to atype which be an instance of Num, it does not mean a type be an instance of Fractional (because Fractional type class is more constrained than Num type class, so a type may not implement some functions required by Fractional type class). If a type does not fully fit the condition Fractional type class requires, how can it be use in the function (/) which asks the arguments type be instance of Fractional. Sorry for not native speaker and really thanks for your patience!
I tested that if a type only fits the parent type class, it cannot be used in a function which requires more constrained type class.
{-# LANGUAGE OverloadedStrings #-}
module Main where
class ParentAPI a where
printPar :: int -> a -> String
class (ParentAPI a) => SubAPI a where
printSub :: a -> String
data ParentDT = ParentDT Int
instance ParentAPI ParentDT where
printPar i p = "par"
testF :: (SubAPI a) => a -> String
testF a = printSub a
main = do
let m = testF $ ParentDT 10000
return ()
====
test-typeclass.hs:19:11: error:
• No instance for (SubAPI ParentDT) arising from a use of ‘testF’
• In the expression: testF $ ParentDT 10000
In an equation for ‘m’: m = testF $ ParentDT 10000
In the expression:
do { let m = testF $ ParentDT 10000;
return () }
I have found a doc explaining the numeric overloading ambiguity very clearly and may help others with the same confusion.
https://www.haskell.org/tutorial/numbers.html
First, note that both Fractional and Num are not types, but type classes. You can read more about them in the documentation or elsewhere, but the basic idea is that they define behaviors for types. Num is the most inclusive numeric typeclass, defining behaviors functions like (+), negate, which are common to pretty much all "numeric types." Fractional is a more constrained type class that describes "fractional numbers, supporting real division."
If we look at the type class definition for Fractional, we see that it is actually defined as a subclass of Num. That is, for a type a to be an have an instance Fractional, it must first be a member of the typeclass Num:
class Num a => Fractional a where
Let's consider some type that is constrained by Fractional. We know it implements the basic behaviors common to all members of Num. However, we can't expect it to implement behaviors from other type classes unless multiple constraints are specified (ex. (Num a, Ord a) => a. Take, for example, the function div :: Integral a => a -> a -> a (integral division). If we try to apply the function with an argument that is constrained by the typeclass Fractional (ex. 1.2 :: Fractional t => t), we encounter an error. Type classes restrict the sort of values a function deals with, allowing us to write more specific and useful functions for types that share behaviors.
Now let's look at the more general typeclass, Num. If we have a type variable a that is only constrained by Num a => a, we know that it will implement the (few) basic behaviors included in the Num type class definition, but we'd need more context to know more. What does this mean practically? We know from our Fractional class declaration that functions defined in the Fractional type class are applied to Num types. However, these Num types are a subset of all possible Num types.
The importance of all this, ultimately, has to do with the ground types (where type class constraints are most commonly seen in functions). a represents a type, with the notation Num a => a telling us that a is a type that includes an instance of the type class Num. a could be any of the types that include the instance (ex. Int, Natural). Thus, if we give a value a general type Num a => a, we know it can implement functions for every type where there is a type class defined. For example:
ghci>> let a = 3 :: (Num a => a)
ghci>> a / 2
1.5
Whereas if we'd defined a as a specific type or in terms of a more constrained type class, we would have not been able to expect the same results:
ghci>> let a = 3 :: Integral a => a
ghci>> a / 2
-- Error: ambiguous type variable
or
ghci>> let a = 3 :: Integer
ghci>> a / 2
-- Error: No instance for (Fractional Integer) arising from a use of ‘/’
(Edit responding to followup question)
This is definitely not the most concrete explanation, so readers feel free to suggest something more rigorous.
Suppose we have a function a that is just a type class constrained version of the id function:
a :: Num a => a -> a
a = id
Let's look at type signatures for some applications of the function:
ghci>> :t (a 3)
(a 3) :: Num a => a
ghci>> :t (a 3.2)
(a 3.2) :: Fractional a => a
While our function had the general type signature, as a result of its application the the type of the application is more restricted.
Now, let's look at the function fromIntegral :: (Num b, Integral a) => a -> b. Here, the return type is the general Num b, and this will be true regardless of input. I think the best way to think of this difference is in terms of precision. fromIntegral takes a more constrained type and makes it less constrained, so we know we'll always expect the result will be constrained by the type class from the signature. However, if we give an input constraint, the actual input could be more restricted than the constraint and the resulting type would reflect that.
The reason why this works comes down to the way universal quantification works. To help explain this I am going to add in explicit forall to the type signatures (which you can do yourself if you enable -XExplicitForAll or any other forall related extension), but if you just removed them (forall a. ... becomes just ...), everything will work fine.
The thing to remember is that when a function involves a type constrained by a typeclass, then what that means is that you can input/output ANY type within that typeclass, so it's actually better to have a less constrained typeclass.
So:
fromInteger :: forall a. Num a => Integer -> a
fromInteger 5 :: forall a. Num a => a
Means that you have a value that is of EVERY Num type. So not only can you use it in a function taking it in a Fractional, you could use it in a function that only takes in MyWeirdTypeclass a => ... as long as there is one single type that implements both Num and MyWeirdTypeclass. Hence why you can get the following just fine:
fromInteger 5 / 2 :: forall a. Fractional a => a
Now of course once you decide to divide by 2, it now wants the output type to be Fractional, and thus 5 and 2 will be interpreted as some Fractional type, so we won't run into issues where we try to divide Int values, as trying to make the above have type Int will fail to type check.
This is really powerful and awesome, but very much unfamiliar, as generally other languages either don't support this, or only support it for input arguments (e.g print in most languages can take in any printable type).
Now you may be curious when the whole superclass / subclass stuff comes into play, so when you are defining a function that takes in something of type Num a => a, then because a user can pass in ANY Num type, you are correct that in this situation you cannot use functions defined on some subclass of Num, only things that work on ALL Num values, like *:
double :: forall a. Num a => a -> a
double n = n * 2 -- in here `n` really has type `exists a. Num a => a`
So the following does not type check, and it wouldn't type check in any language, because you don't know that the argument is a Fractional.
halve :: Num a => a -> a
halve n = n / 2 -- in here `n` really has type `exists a. Num a => a`
What we have up above with fromInteger 5 / 2 is more equivalent to the following, higher rank function, note that the forall within parenthesis is required, and you need to use -XRankNTypes:
halve :: forall b. Fractional b => (forall a. Num a => a) -> b
halve n = n / 2 -- in here `n` has type `forall a. Num a => a`
Since this time you are taking in EVERY Num type (just like the fromInteger 5 you were dealing with before), not just ANY Num type. Now the downside of this function (and one reason why no one wants it) is that you really do have to pass in something of EVERY Num type:
halve (2 :: Int) -- does not work
halve (3 :: Integer) -- does not work
halve (1 :: Double) -- does not work
halve (4 :: Num a => a) -- works!
halve (fromInteger 5) -- also works!
I hope that clears things up a little. All you need for the fromInteger 5 / 2 to work is that there exists ONE single type that is both a Num and a Fractional, or in other words just a Fractional, since Fractional implies Num. Type defaulting doesn't help much with clearing up this confusion, as what you may not realize is that GHC is just arbitrarily picking Double, it could have picked any Fractional.

Polymorphism: a constant versus a function

I'm new to Haskell and come across a slightly puzzling example for me in the Haskell Programming from First Principles book. At the end of Chapter 6 it suddenly occurred to me that the following doesn't work:
constant :: (Num a) => a
constant = 1.0
However, the following works fine:
f :: (Num a) => a -> a
f x = 3*x
I can input any numerical value for x into the function f and nothing will break. It's not constrained to taking integers. This makes sense to me intuitively. But the example with the constant is totally confusing to me.
Over on a reddit thread for the book it was explained (paraphrasing) that the reason why the constant example doesn't work is that the type declaration forces the value of constant to only be things which aren't more specific than Num. So trying to assign a value to it which is from a subclass of Num like Fractional isn't kosher.
If that explanation is correct, then am I wrong in thinking that these two examples seem completely opposites of each other? In one case, the type declaration forces the value to be as general as possible. In the other case, the accepted values for the function can be anything that implements Num.
Can anyone set me straight on this?
It can sometimes help to read types as a game played between two actors, the implementor of the type and the user of the type. To do a good job of explaining this perspective, we have to introduce something that Haskell hides from you by default: we will add binders for all type variables. So your types would actually become:
constant :: forall a. Num a => a
f :: forall a. Num a => a -> a
Now, we will read type formation rules thusly:
forall a. t means: the caller chooses a type a, and the game continues as t
c => t means: the caller shows that constraint c holds, and the game continues as t
t -> t' means: the caller chooses a value of type t, and the game continues as t'
t (where t is a monomorphic type such as a bare variable or Integer or similar) means: the implementor produces a value of type a
We will need a few other details to truly understand things here, so I will quickly say them here:
When we write a number with no decimal points, the compiler implicitly converts this to a call to fromInteger applied to the Integer produced by parsing that number. We have fromInteger :: forall a. Num a => Integer -> a.
When we write a number with decimal points, the compiler implicitly converts this to a call to fromRational applied to the Rational produced by parsing that number. We have fromRational :: forall a. Fractional a => Rational -> a.
The Num class includes the method (*) :: forall a. Num a => a -> a -> a.
Now let's try to walk through your two examples slowly and carefully.
constant :: forall a. Num a => a
constant = 1.0 {- = fromRational (1 % 1) -}
The type of constant says: the caller chooses a type, shows that this type implements Num, and then the implementor must produce a value of that type. Now the implementor tries to play his own game by calling fromRational :: Fractional a => Rational -> a. He chooses the same type the caller did, and then makes an attempt to show that this type implements Fractional. Oops! He can't show that, because the only thing the caller proved to him was that a implements Num -- which doesn't guarantee that a also implements Fractional. Dang. So the implementor of constant isn't allowed to call fromRational at that type.
Now, let's look at f:
f :: forall a. Num a => a -> a
f x = 3*x {- = fromInteger 3 * x -}
The type of f says: the caller chooses a type, shows that the type implements Num, and chooses a value of that type. The implementor must then produce another value of that type. He is going to do this by playing his own game with (*) and fromInteger. In particular, he chooses the same type the caller did. But now fromInteger and (*) only demand that he prove that this type is an instance of Num -- so he passes off the proof the caller gave him of this and saves the day! Then he chooses the Integer 3 for the argument to fromInteger, and chooses the result of this and the value the caller handed him as the two arguments to (*). Everybody is satisfied, and the implementor gets to return a new value.
The point of this whole exposition is this: the Num constraint in both cases is enforcing exactly the same thing, namely, that whatever type we choose to instantiate a at must be a member of the Num class. It's just that in the definition constant = 1.0 being in Num isn't enough to do the operations we've written, whereas in f x = 3*x being in Num is enough to do the operations we've written. And since the operations we've chosen for the two things are so different, it should not be too surprising that one works and the other doesn't!
When you have a polymorphic value, the caller chooses which concrete type to use. The Haskell report defines the type of numeric literals, namely:
integer and floating literals have the typings (Num a) => a and
(Fractional a) => a, respectively
3 is an integer literal so has type Num a => a and (*) has type Num a => a -> a -> a so f has type Num a => a -> a.
In contrast, 3.0 has type Fractional a => a. Since Fractional is a subclass of Num your type signature for constant is invalid since the caller could choose a type for a which is Num but not Fractional e.g. Int or Integer.
They don't mean the opposite - they mean exactly the same ("as general as possible"). Typeclass gives you all guarantees that you can rely upon - if typeclass T provides function f, you can use it for all instances of T, but even if some of these instances are members of G (providing g) as well, requiring to be of T typeclass is not sufficient to call g.
In your case this means:
Members of Num are guaranteed to provide conversion from integers (i.e. default type for integral values, like 1 or 1000) - with fromInteger function.
However, they are not guaranteed to provide conversion from rational numbers (like 1.0) - Fractional typeclass does provide this as fromRational function, but it doesn't really matter, as you use only Num.

Can't input values into function, because type cannot be deduced

I wanted to write a simple recursive function to help me check some values of a maths problem, however I can't seem to add any valid inputs.
Here's the function in question
fun 1 = 1
fun n = fun (ceiling n) + 3
It appears to be of type (Integral a1, Num a, RealFrac a1) => a1 -> a
Giving fun any number as input yields the following error:
Could not deduce (Integral a10) arising from a use of ‘fun’
from the context (Num a)
bound by the inferred type of it :: Num a =>
Look at the inferred type signature, you have Integral a1 and RealFrac a1 as constraints, and the function overall just returns a Num a. What you're saying is that this function takes a type that is both an Integral and RealFrac, already a contradiction logically but technically possible to implement in Haskell, and returns any numeric type whatsoever. This comes from your use of ceiling, which has the type (Integral b, RealFrac a) => a -> b, which you then pass to fun again. So n must be an Integral, but since you pass the result of ceiling n to fun it must also be a RealFrac. The second problem is that you simply haven't given the compiler enough information to know exactly which types you're wanting to use.
My first suggestion is to give fun the type signature you think it should have, which I'm guessing is probably Double -> Int. If you do this you'll get a type error of No instance for (Integral Double) arising from use of ceiling ..., meaning that you're trying to use a Double as an Integral when Double doesn't implement Integral for obvious reasons. This tells you precisely which part of your definition is suspect. You can choose to cast the result of ceiling to Double using fromIntegral or fromInteger.
Beyond all this, this function will never terminate unless it's called with the value 1. It will essentially just build up a giant thunk of adding 3 over and over again and will just eat up RAM and CPU.
That's because ceiling returns an Integral, and you're recursively calling fun with that value, so it deduces that fun must accept Integral values, but ceiling takes RealFrac values, and you're passing to ceiling the argument you got from the application of fun, so it deduces that fun must also take RealFrac values. Hence the constraints.
In situations like this, it's best to limit the options Haskell considers during type inference by annotation your function with the type you think it should have — the error message will become more concrete/narrowed down then and will be more localized to the code under question; otherwise, type inference will analyze your entire program and consider too many options.
(also the function itself is ill-defined as the other answer points out, but that is not causing the type error, obviously)

Why does "(1 + 1.0)" have the type "Fractional a => a" and not "Num a => a"?

1 has the type Num a => a
1.0 has the type Fractional a => a
Why does 1+1.0 have the type Fractional a => a
This seems strange to me because 1 is not fractional. Only 1.0 is fractional. So how did 1 turn into fractional and get combined with 1.0 to form a fractional?
Since only Num has the + operator, it would seem more natural to me if 1.0 turned into Num, got combined with 1 to produce a final Num (although that would be strange too because we would lose information going from 1.0 to 1).
Every Fractional is a Num, but not every Num is a Fractional. So if we have a Num like 1, it could either be a Fractional (because some Nums are Fractionals) or it could not be. However 1.0 can only be a Fractional, it definitely can't be some other Num like Integer.
So when the compiler sees that you add 1 to a Fractional, it realizes that 1 must be a Fractional as well in this case - otherwise you'd not be allowed to add it to a Fractional.
Here's an example of a similar example that only involves user-defined type classes instead of Nums. Maybe this makes things clearer for you:
class Foo a where
foo :: a
class Foo a => Bar a where
bar :: a
combine :: a -> a -> a
Through the above type classes we now have the following methods:
foo :: Foo a => a
bar :: Bar a => a
combine :: Bar a => a -> a -> a
So now let's try to combine foo and bar like this:
combine foo bar
This is roughly equivalent to you trying to add 1 (of type Num a => a) and 1.0 (of type Fractional a => a) in your example. And just like your example, this works fine and has the type Bar a => a.
Type classes are very much not like OO classes, this can't be overemphasized.
In particular, “if 1.0 turned into Num” doesn't make any sense. Num is a type class, not a type, so nothing can ever “turn into a Num”. In fact, nothing ever turns into something else at all in Haskell – everything has a concrete type, that is fixed.
Now you ask, how do polymorphic functions work then? Well, it's called parametric polymorphism for a reason: what seems to be an “arbitrary type a” is really a type parameter. Like a function parameter, these aren't variables in the sense that they can ever change their value after the fact, but they are variable in the sense that the caller of the function is allowed to choose any particular “type value” for a – provided it fulfills the type-class constraint.
So in a sense, the literal 1 is a function: it accepts a type argument a, and returns a value 1 :: a. What it requires is that a is in class Num.
Then we have (+) and 1.0, both of which also need that same a argument. (+) again requires Num, nothing new; but 1.0 requires Fractional a. So all in all, 1 + 1.0 is a function that accepts “three copies of” the type argument a, and requires
Num a
Num a
Fractional a – which also requires Num a because Num is superclass of Fractional.
It would be pretty awkward if we actually had to write the type out as
(1 + 1.0) :: (Num a, Num a, Fractional a, Num a) => a
so it is allowed to leave out the redundant constraints, only leaving Fractional a, which implies all the rest. What we can't do is only leave one of the Num constraints, because that would not imply Fractional.
Number 1 (which technically stands for fromInteger applied to the Integer value 1) belongs to all the types in class Num.
All the types in class Fractional belong to class Num as well.
Ergo,
Number 1 belongs to all the types in class Fractional.

Resources