I defined a function that computes sqrt and converts argument from and to Integral class:
isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral
I don't understand why that compiles. If we write out signatures of the individual functions we get:
fromIntegral :: (Num b, Integral a) => a -> b
sqrt :: Floating a => a -> a
floor :: (RealFrac a, Integral b) => a -> b
So "sqrt" takes something of Floating type but it is supplied with Num. If you take a look at class hierarchy, you can see that Floating "inherits" from Num but not the other way around. I would understand if Floating could be implicitly treated as Num because it is a more "specialized" type. Why this is OK for the compiler ?
No,
sqrtis not supplied with anyNum.Its supplier
fromIntegralis able to produce anyNumas needed indeed, whereassqrtdemands aFloatingas its input. AndFloatingis a subclass ofNum.So
fromIntegralhappily obliges. Since it can produce anyNum, surely it can produce any type in any subclass ofNum. So whatever the specific concrete type it ends up to be, it is inFloating, and thus necessarily it is inNum.Thus
fromIntegralhas no problem providing it.edit:
Floatingis not a type. It is a class of types. A concrete type might be inFloatingclass of types. SinceFloatingis a subclass ofNum, such type is also guaranteed to be inNum. It is not something that happens automatically due to "inheritance" that you mention. That "inheritance" i.e. subclass relation is a requirement on that specific type which isFloatingto also be (in)Numi.e. to implementNum's methods as well as the ones fromFloating.So yes, a (specific, concrete)
Floatingtype can also be treated as aNumtype.On the other side of things,
sqrtproduces the same type as its input type, so it will be the same concreteFloatingtype. Butfloorexpects aRealFractype.Observe
So the concrete type produced (and thus, accepted) by that
sqrtcall must be (in)RealFracas well asFloating.Since it is not observed from outside of that application chain it could be any compliant type, and is thus ambiguous; but type defaulting kicks in and selects
Double, unless you've changed the defaults.