Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Haskell: YesNo type class. Why Integer?

Tags:

I have a question on how GHCi assumes type of a whole number.

I was reading Yes-No type class of Learn you a Haskell.

Here is a link if you want to read the whole thing. http://learnyouahaskell.com/making-our-own-types-and-typeclasses#a-yes-no-typeclass

To put it shortly, this chapter shows that by defining my own class, I can make a function that works with a lot of types.

This book defines YesNo class with a function

yesno :: a -> Bool 

and make Int as a instance of YesNo class

instance YesNo Int where     yesno 0 = False     yesno _ = True 

When I loaded this on my GHCi and typed

yesno 0 

it returned error. I thought it is probably because GHCi cannot tell whether 0 is meant to be Int or Integer or Double or other type in Num class. Actually when I typed yesno (0::Int) it worked.

So just for fun I made Integer as an instance of YesNo class and wrote

instance YesNo Integer where     yesno 0 = True     yesno _ = False 

(Note that I flipped True and False) and again, I typed

yesno 0 

(without any type declaration) then GHCi showed True.

Moreover, when I typed

yesno $ fromIntegral 0 

it returned True, which means that GHCi thinks the type of fromIntegral 0 is Integer.

So, does this mean that when I just type a whole number on GHCi, it usually assumes its value is Integer in stead of? I am confused because :t 0 returns Num a => a

like image 331
Tengu Avatar asked May 29 '13 21:05

Tengu


2 Answers

It's type defaulting together with ghci's extended default rules.

Integer literals are polymorphic, they have the type Num a => a (since they stand for fromInteger literal). But when an expression shall be evaluated - necessary for printing its result, for example - the expression must be given a monomorphic type.

By itself,

yesno 0 

imposes the two constraints Num a and YesNo a on the 0, and the entire expression would have the ambiguous type

yesno 0 :: (Num a, YesNo a) => Bool 

(it's ambiguous, since the type variable in the constraint is not reachable from the type on the right of the =>).

Generally, ambiguous types are type errors, however, in some cases the ambiguity is resolved by instantiating the constrained type variable with a default type. The rules in the language specification are that a type variable can be defaulted if

In situations where an ambiguous type is discovered, an ambiguous type variable, v, is defaultable if:

- `v` appears only in constraints of the form `C v`, where `C` is a class, and - at least one of these classes is a numeric class, (that is, `Num` or a subclass of `Num`), and - all of these classes are defined in the Prelude or a standard library (Figures 6.2–6.3 show the numeric classes, and Figure 6.1 shows the classes defined in the Prelude.) 

The constraint (Num a, YesNo a) meets the first two requirements, but not the third. So by the language standard, it is not defaultable and should be a type error.

However, ghci uses extended default rules and also defaults type variables constrained by classes not defined in the Prelude or the standard libraries.

It would then choose the default for a Num constraint here, unless an explicit default declaration is in scope, that would be Integer, or, if Integer does not satisfy the constraints, Double is tried.

So when you have an instance YesNo Integer, ghci can successfully default the type variable a to Integer. But with no such instance available, defaulting fails because none of the default candidates has an instance.

like image 50
Daniel Fischer Avatar answered Sep 18 '22 23:09

Daniel Fischer


So, does this mean that when I just type a whole number on GHCi, it usually assumes its value is Integer?

Yes. Basically, GHCi will first try Integer, then if that fails, Double and then finally () to resolve ambiguous type constraints. You can read the details about how this works in the GHC User's Guide.

However, note that in compiled modules, the rules are a bit stricter. In particular, defaulting only applies to standard classes, so your example won't work without a type annotation in a compiled module unless you enable the ExtendedDefaultRules extension which gives you the same behavior as GHCi.

like image 27
hammar Avatar answered Sep 22 '22 23:09

hammar