Int vs Integer in class instance
class Visible a where
toString :: a -> String
size :: a -> Int
intToString :: (Integral t) => t -> String
intToString 0 = "0"
intToString 1 = "1"
intToString 2 = "2"
intToString 3 = "3"
intToString 4 = "4"
开发者_高级运维intToString 5 = "5"
intToString 6 = "6"
intToString 7 = "7"
intToString 8 = "8"
intToString 9 = "9"
intToString n
| ((div n 10) == 0) = (intToString (mod n 10))
| otherwise = (intToString (div n 10)) ++ (intToString (mod n 10))
Now
instance Visible Int where
toString = intToString
size n = length (toString n)
gives me an error about an ambiguous type variable at the prompt if I type something like (toString 55)
but
instance Visible Integer where
toString = intToString
size n = length (toString n)
does not.
What gives?
There are two things going on here. Remember that numeric literals in Haskell are polymorphic. That is:
x = 55
really means
x :: Num a => a
x = fromIntegral 55
This is true for all numbers anywhere you write them. This can be awkward to work with, so GHCi implements type defaulting: it assumes that bare numbers are Integers
or Doubles
if the type is ambiguous.
When you write toString 55
at the GHCi prompt, GHCi infers the type (Visible a, Num a) => a
for the number 55. If you only have Visible Int
in scope, the type default of Integer
doesn't work because it doesn't fulfill the class constraint (there's no Visible Integer
), so GHCi complains about the ambiguous type variable because it doesn't know which type to instantiate for the expression. If you do have Visible Integer
in scope, the type default of Integer works just fine.
If you want to use a type other than Integer, you can use an explicit type as in toString (55 :: Int)
I found at this link a possible explanation. I think the default interpretation of a literal is an Integer in ghci. But if that doesn't work out, ghci starts being confused about which interpretation of the literal he must make (Int, Double, Float, ...).
Subsequently he gives the error about ambiguity. The command (toString (55:Int)
) gives no error because GHCi knows he has to interprete the 55
as an Int
.
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,
精彩评论