我定义了一个函数,用于计算sqrt
并将参数从Integral
类转换为CCD_2:
isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral
我不明白为什么会编译。如果我们写出我们得到的各个函数的签名:
fromIntegral :: (Num b, Integral a) => a -> b
sqrt :: Floating a => a -> a
floor :: (RealFrac a, Integral b) => a -> b
所以"CCD_ 3";采用Floating
类型的东西,但是它被提供有Num
。如果你看一看类的层次结构,你可以看到Floating
"继承";而不是相反。如果CCD_ 8可以隐式地被视为CCD_;专用的";类型为什么这对编译器来说是可以的?
否,sqrt
不是随任何Num
提供的
其供应商fromIntegral
能够根据需要生产任何Num
,而sqrt
需要Floating
作为其输入。CCD_ 16是CCD_ 17的子类。
所以fromIntegral
愉快地答应了。既然它可以产生任何Num
,那么它肯定可以在Num
的任何子类中产生任何类型。因此,无论它最终是什么具体类型,它都在Floating
中,因此必然在Num
中。
因此fromIntegral
提供它没有问题
edit:Floating
不是类型。它是一类类型。具体类型可能在Floating
类型类中。由于Floating
是Num
的一个子类,因此也保证该类型在Num
中。这不是由于";"继承";你提到的。";"继承";即子类关系是对CCD_ 29的特定类型的要求也在CCD_ 30中,即实现CCD_ 31的方法以及来自CCD_ 32的方法。
因此,是的,(特定的、具体的(sqrt
3类型也可以被视为Num
类型。
另一方面,sqrt
产生的类型与其输入类型相同,因此它将是相同的具体Floating
类型。但是floor
期望RealFrac
类型。
观察
> :t floor ----------
floor :: (Integral b, RealFrac a) => a -> b
> :t sqrt . fromIntegral ----------
sqrt . fromIntegral :: (Integral a, Floating c) => a -> c
> :t floor . sqrt ---------- ----------
floor . sqrt :: (Integral c, RealFrac b, Floating b) => b -> c
> :i Floating
class Fractional a => Floating a where
....
instance Floating Float
instance Floating Double
> :i RealFrac
class (Real a, Fractional a) => RealFrac a where
....
instance RealFrac Float
instance RealFrac Double
因此,sqrt
调用产生(并因此接受(的具体类型必须是(在(RealFrac
和Floating
。
由于没有从应用程序链外部观察到它,因此它可以是任何兼容类型,因此不明确;但类型defaulting会启动并选择Double
,除非您更改了默认值。
因此
sqrt
采用Floating
类型,但随Num
一起提供。
否。fromIntegral
保证它可以将类型为Integral
类型类成员的任意数字转换为任何Num
类型,而不是转换为一个Num
类型。
由于sqrt
需要一个作为Floating
类型类成员的数字,因此对于该特定情况,fromIntegral
将特别返回属于Floating
类型类成员类型的东西。