The literal 2
is of type Num a => a
. That is, it can be any numerical type. Specifically, Haskell will take the integer value 2
and call fromInteger
on it (which is defined for any Num
). So when you write
sqrt 2
Internally, what's happening is
sqrt (fromInteger 2) :: Floating a => a
And if you force the value, such as in GHCi, you'll get a Double
since that's the default for Floating
.
Likewise, the type of round (sqrt 2)
is going to be Integral b => b
and is going to require the sqrt 2
type to be RealFrac a => a
. There exist types which are both RealFrac
and Floating
, so that's not a contradiction. In particular, GHC will happily default to Double
here for the same reason as before. If you force the value to be printed, the entire result (Integral b => b
) will default to Integer
.
It's important to remember that all of these are universally quantified. Floating a => a
doesn't mean "this is some floating type and that's all I know". It means "if you have any floating type, I can produce a value of that type". You get to choose which floating type to use, so if a constraint comes along later and says the value is also RealFrac a => a
, that's fine because we've simply constrained ourselves to be both Floating
and RealFrac
. This is contrary to a language like Java, where if I have a value of some interface type, say Comparable
, then all I can conclude is that it's some Comparable
type, not that it works for all of them.
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…