开发者

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,

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜