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 ?
CodePudding user response:
So
sqrt
takes something ofFloating
type but it is supplied withNum
.
No. The fromIntegral
guarantees that it can convert any number with a type that is a member of the Integral
typeclass to any Num
type, not to a Num
type.
Since sqrt
needs an number that is a member of the Floating
typeclass, for that specific case, fromIntegral
will specialy to return something of a type that is a member of the Floating
typeclass.
CodePudding user response:
No, sqrt
is not supplied with any Num
.
Its supplier fromIntegral
is able to produce any Num
indeed as needed, whereas sqrt
demands a Floating
as its input. And Floating
is a subclass of Num
.
So fromIntegral
happily obliges. Since it can produce any Num
, surely it can produce any type in its subclass. So whatever the specific concrete type it ends up to be, it is in Floating
, and necessarily it is in Num
.
Thus fromIntegral
has no problem to provide it.