为什么 Num 在 haskell 中可以被视为 Floating?
Why Num can be treated as Floating in haskell?
我定义了一个函数来计算 sqrt
并将参数从 Integral
转换为 class:
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
所以“sqrt
”采用了 Floating
类型的东西,但它是由 Num
提供的。如果你看一下 class hierarchy,你会发现 Floating
从 Num
“继承”,而不是相反。我会理解 Floating
是否可以被隐含地视为 Num
因为它是一种更“专业”的类型。为什么这对编译器来说没问题?
不,sqrt
不随任何Num
提供。
它的供应商fromIntegral
确实能够生产确实需要Num
,而sqrt
需要一个 Floating
作为它的输入。并且 Floating
是 subclass of Num
.
所以 fromIntegral
很高兴地答应了。既然它可以产生任何Num
,那么它肯定可以产生Num
的任何子class中的任何类型。因此,无论它最终是什么特定的具体类型,它都在 Floating
中,因此它必然在 Num
.
中
因此 fromIntegral
提供它没有问题。
编辑: Floating
不是类型。它是一个 class 类型。具体类型可能在 Floating
class 类型中。由于 Floating
是 Num
的子 class,因此这种类型也保证在 Num
中。这不是由于您提到的“继承”而自动发生的事情。 “继承”即 subclass 关系是 要求 对特定类型的 Floating
也是 (in) Num
即实现Num
的方法以及Floating
.
的方法
所以是的,(具体的,具体的)Floating
类型也可以被视为 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
.
由于无法从该应用程序链外部观察到它,因此它可以是任何兼容类型,因此 不明确;但是 type defaulting 启动并选择 Double
,除非您更改了默认值。
So sqrt
takes something of Floating
type but it is supplied with Num
.
否。 fromIntegral
保证它可以将属于 Integral
类型类成员的 any 数字转换为 any Num
类型,不是aNum
类型。
由于 sqrt
需要一个属于 Floating
类型类成员的数字,对于这种特定情况,fromIntegral
将专门针对 return 某种类型是 Floating
类型类的成员。
我定义了一个函数来计算 sqrt
并将参数从 Integral
转换为 class:
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
所以“sqrt
”采用了 Floating
类型的东西,但它是由 Num
提供的。如果你看一下 class hierarchy,你会发现 Floating
从 Num
“继承”,而不是相反。我会理解 Floating
是否可以被隐含地视为 Num
因为它是一种更“专业”的类型。为什么这对编译器来说没问题?
不,sqrt
不随任何Num
提供。
它的供应商fromIntegral
确实能够生产确实需要Num
,而sqrt
需要一个 Floating
作为它的输入。并且 Floating
是 subclass of Num
.
所以 fromIntegral
很高兴地答应了。既然它可以产生任何Num
,那么它肯定可以产生Num
的任何子class中的任何类型。因此,无论它最终是什么特定的具体类型,它都在 Floating
中,因此它必然在 Num
.
因此 fromIntegral
提供它没有问题。
编辑: Floating
不是类型。它是一个 class 类型。具体类型可能在 Floating
class 类型中。由于 Floating
是 Num
的子 class,因此这种类型也保证在 Num
中。这不是由于您提到的“继承”而自动发生的事情。 “继承”即 subclass 关系是 要求 对特定类型的 Floating
也是 (in) Num
即实现Num
的方法以及Floating
.
所以是的,(具体的,具体的)Floating
类型也可以被视为 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
.
由于无法从该应用程序链外部观察到它,因此它可以是任何兼容类型,因此 不明确;但是 type defaulting 启动并选择 Double
,除非您更改了默认值。
So
sqrt
takes something ofFloating
type but it is supplied withNum
.
否。 fromIntegral
保证它可以将属于 Integral
类型类成员的 any 数字转换为 any Num
类型,不是aNum
类型。
由于 sqrt
需要一个属于 Floating
类型类成员的数字,对于这种特定情况,fromIntegral
将专门针对 return 某种类型是 Floating
类型类的成员。