
Hello! I was very surprised to see that Int and Integer seem to differ with respect to ambiguity. And I have no idea what is going on. This works as intended: data AW = AI Integer deriving (Show, Eq, Ord) class AWC a where toAW :: a -> AW fromAW :: AW -> a instance AWC Integer where toAW = AI fromAW (AI v) = v
toAW 5 5
However, the following gives an error: data AW = AI Int deriving (Show, Eq, Ord) class AWC a where toAW :: a -> AW fromAW :: AW -> a instance AWC Int where toAW = AI fromAW (AI v) = v
toAW 5 Ambiguous type variable 't' in the constraints: 'Num t' arising from the literal '5' 'AWC t' arising from the use of 'toAW'
Ok, I can fix this easily with
toAW (5::Int)
But I still don't understand what's going on? Why does one type work and the other does not? Is there a way around this without type annotations? Any hint would be greatly appreciated! Thanks in advance, Thomas

Hi. So this fragment works:
data AW = AI Integer deriving (Show, Eq, Ord)
class AWC a where toAW :: a -> AW fromAW :: AW -> a
instance AWC Integer where toAW = AI fromAW (AI v) = v
toAW 5 5
But replacing Integer by Int everywhere above yields
toAW 5 Ambiguous type variable 't' in the constraints: 'Num t' arising from the literal '5' 'AWC t' arising from the use of 'toAW'
The reason for this behaviour is a dark(er) corner of Haskell called "defaulting", described in Section 4.3.4 of the Haskell Report. Look at what ghci says about 5:
:t 5 5 :: (Num t) => t
So, the literal 5 can be interpreted as any numeric type. This is nice, because it allows us to use 5 as an integer, as in
:t length [] + 5 length [] + 5 :: Int
or as a floating point number
:t sin pi + 5 sin pi + 5 :: (Floating a) => a
(Note that the latter type is still overloaded, as Floating can be instantiated to either Float or Double.) Now, your method toAW has the type (AWC a) => a -> AW You apply this method not to a value of a specific type, but to a value of another overloaded type, namely your literal 5. This means that Haskell has to figure out which concrete type to choose for "a" in this case. Haskell's type classes are open, and it usually does not randomly pick one if multiple *might* match. In this case, there is an instance for Integer (in your first example) or Int (in your second), but there might as well be another one for Float or Double. Which one would be the right one? Well, as I said, usually Haskell is conservative here and just complains, hence the "Ambiguous type variable" error you get in the second case. However, there is a mechanism in Haskell to give heuristics, and that's what "defaulting" is all about. Under normal circumstances, Haskell will, for numeric types, pick "Integer" in cases of ambiguity, and if that doesn't work, it will try "Double". It does not try "Int" though. This explains why your first example (by accident) works. If you ask GHCi for the type, defaulting isn't applied, but you can observe it to happen in many places. For example,
show 5 "5"
show (5 :: Double) "5.0"
So, apparently, Haskell decides to show an unconstrained numeral like an Integer, not like a Double. A more conclusive example is
Data.Typeable.typeOf 5 Integer
Defaulting to Double if Integer is ruled out can be observed by
Data.Typeable.typeOf (sin pi) Double
Cheers, Andres -- Andres Loeh, Universiteit Utrecht mailto:andres@cs.uu.nl mailto:mail@andres-loeh.de http://www.andres-loeh.de

On Monday 17 May 2010 18:44:11, Thomas wrote:
Hello!
I was very surprised to see that Int and Integer seem to differ with respect to ambiguity. And I have no idea what is going on.
This works as intended: data AW = AI Integer deriving (Show, Eq, Ord)
class AWC a where toAW :: a -> AW fromAW :: AW -> a
instance AWC Integer where toAW = AI fromAW (AI v) = v
toAW 5
5
However, the following gives an error: data AW = AI Int deriving (Show, Eq, Ord)
class AWC a where toAW :: a -> AW fromAW :: AW -> a
instance AWC Int where toAW = AI fromAW (AI v) = v
toAW 5
Ambiguous type variable 't' in the constraints: 'Num t' arising from the literal '5' 'AWC t' arising from the use of 'toAW'
Ok, I can fix this easily with
toAW (5::Int)
But I still don't understand what's going on?
The literal 5 (which is implicitly 'fromInteger 5'), can have any type which is a member of Num, so in toAW 5 , the type of 5 is ambiguous. For convenience, in some cases, a Haskell implementation tries to resolve such ambiguities by defaulting (http://haskell.org/onlinereport/decls.html#sect4.3.4). The default-default is (Integer, Double), that means, if an ambiguity can be resolved by choosing the type Integer, that is chosen, otherwise Double is tried. You can give different defaults in a module, so e.g. a default declaration default (Int, Integer, Rational, Double) would try Int first. However, according to the defaulting rules in the report, no defaulting would take place here, since there's a class (AWC) involved which isn't defined in the standard libraries. But ghci uses relaxed defaulting rules (to resolve more cases, otherwise 'ambiguous type' errors would be much more frequent), so it tries to resolve the ambiguity although AWC isn't defined in the standard libraries. In the first case, choosing Integer for the type works, so it takes Integer for the type of 5 and all's well. In the second case, Integer doesn't work, nor does Double, so it can't resolve the ambiguity. Unfortunately, when ghci loads a module, it ignores default declarations, so you couldn't get it to work by adding default declaration including Int.
Why does one type work and the other does not? Is there a way around this without type annotations?
No, not at the ghci prompt. In normal code, usually the type of such a value could be determined from other things (when you use it in a function, there's much more contextual information than when you enter such an expression at the prompt). For uses inside the module, you can have some success with {-# LANGUAGE ExtendedDefaultRules #-} module AWC where default (Int, Integer, Double) data AW = AI Int deriving (...) ... if not all uses allow the type to be determined from the context.
Any hint would be greatly appreciated! Thanks in advance, Thomas
participants (3)
-
Andres Loeh
-
Daniel Fischer
-
Thomas