为什么 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,你会发现 FloatingNum “继承”,而不是相反。我会理解 Floating 是否可以被隐含地视为 Num 因为它是一种更“专业”的类型。为什么这对编译器来说没问题?

不,sqrt 任何Num提供。

它的供应商fromIntegral确实能够生产确实需要Num,而sqrt 需要一个 Floating 作为它的输入。并且 Floating subclass of Num.

所以 fromIntegral 很高兴地答应了。既然它可以产生任何Num,那么它肯定可以产生Num的任何子class中的任何类型。因此,无论它最终是什么特定的具体类型,它都在 Floating 中,因此它必然在 Num.

因此 fromIntegral 提供它没有问题。

编辑: Floating 不是类型。它是一个 class 类型。具体类型可能在 Floating class 类型中。由于 FloatingNum 的子 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 类型类的成员。