See section 4.3.4 in the Haskell report. When Haskell reads a literal that looks integral (no decimal component), the type is (unless more specifically inferred) Num a => a
. The moment it needs to choose a type, it uses the defaulting rules, and normally the default is Integer
. When a literal has a decimal component, it is Fractional a => a
, which is normally defaulted to Double
.
By using a default
top-level declaration, you can change these settings, e.g.:
default (Int, Float)
would default Num
to Int
and Fractional
to Float
(because Int
is not Fractional
). Note that the effect of this statement is local to the module in which it is declared.
The default statement has the following effect (quoting the report):
Each defaultable variable is replaced by the first type in the default list that is an instance of all the ambiguous variable’s classes. It is a static error if no such type is found.
The -XExtendedDefaultRules GHC flag has additional effects, see here.
Edit
As for your error, the source is the following statement, which is in the GHC user guide and in different wording in section 4.3.4 of the report:
However, it is tiresome for the user to have to specify the type, so GHCi extends Haskell's type-defaulting rules (Section 4.3.4 of the Haskell 2010 Report) as follows. The standard rules take each group of constraints (C1 a, C2 a, ..., Cn a) for each type variable a, and defaults the type variable if
The type variable a appears in no other constraints
All the classes Ci are standard.
At least one of the classes Ci is numeric.
Where I intentionally put focus on the second bullet. Because you're using .+.
, one of the classes of the numbers is MyFuns
- which is not a class from the Prelude or the standard library, so it is not a "standard" class. Luckily, the text continues as follows:
At the GHCi prompt, or with GHC if the -XExtendedDefaultRules flag is given, the following additional differences apply:
Rule 2 above is relaxed thus: All of the classes Ci are single-parameter type classes.
Rule 3 above is relaxed this: At least one of the classes Ci is numeric, or is Show, Eq, or Ord.
The unit type () is added to the start of the standard list of types which are tried when doing type defaulting.
In conclusion, if you use the ExtendedDefaultRules
flag (which as you can see is active in GHCi by default), your code will compile just fine also with your custom class:
{-# LANGUAGE ExtendedDefaultRules #-}
import Debug.Trace
default (Int, Float, Double)
class MyFuns a where
(.+.) :: a -> a -> a
instance MyFuns Double where
x .+. y = trace "Double " $ x + y
instance MyFuns Integer where
x .+. y = trace "Integer " $ x + y
instance MyFuns Int where
x .+. y = trace "Int " $ x + y
main = do
print $ 1 .+. 2 -- Interpreted as Int
Note that in this example 1.0 .+. 2.0
is interpreted as double, while 1.0 + 2.0
is interpreted as float: this is because there is no MyFuns
instance for Float, so its entry in the default
list is skipped.