将fractional的类型设置为num

时间:2017-02-11 11:27:32

标签: haskell typeclass

有人可以解释为什么这会编译

Prelude> 1 :: Num a => a

这并不是

Prelude> 1.0 :: Num a => a

第二个示例适用于Fractional,但NumFractional的超类。就像它的Integral的超类一样。

3 个答案:

答案 0 :(得分:5)

如果我们有

x :: Num a => a

x的用户可以根据需要选择a。 E.g。

x :: Int

如果x = 1.5

会评估什么?

由于这个原因,浮点文字不能被赋予多义类型Num a => a,因为它的值不会(通常)适合所有Num个eric类型。

积分文字适合所有数字类型,因此允许使用它们。

答案 1 :(得分:3)

类型类之间的超类关系建立类型之间的关系。它只告诉我们,如果类型 t 是类型类 C 的成员, B C 的超类,然后 t 也将是 B 的成员。

没有说每个值 v :: t 都可以用于 B 成员的任何类型。但这就是你所说的:

3.14159 :: Num a => a

答案 2 :(得分:3)

区分OO语言中的多态性和Haskell中的多态性非常重要。 OO polymorphism is covariant, while Haskell's parametric polymorphism is contravariant

这意味着:用OO语言,如果你有

class A {...}
class B: A {...}

即。 AB的超类,然后类型B的任何值也是类型A的值。 (请注意,任何特定的实际上都不是多态的,而是具体的类型!)因此,如果你有

class Num {...}
class Fractional: Num {...}

然后Fractional值确实可以用作Num值。这大致是协变的意思:任何子类值is also a superclass value;值层次结构与类型层次结构的方向相同。

在Haskell中,class es是不同的。没有“类型Num的值”这样的东西,只有具体类型a的值。 type 可能位于Num类。

与OO语言不同,像1 :: Num a => a 这样的值是多态的:它可以采用环境要求的任何类型,只要类型在Num类中。 (实际上,语法只是1 :: ∀ a . Num a => a的简写,要读作“对于所有类型a,您可以使用1类型的值a。”例如,

Prelude> let x = 1 :: Num a => a
Prelude> x :: Int
1
Prelude> x :: Double
1.0

您还可以为x提供Fractional更具体的约束,因为它是Num的子类。这只是限制了多态值可以实例化的类型:

Prelude> let x = 1 :: Fractional a => a
Prelude> x :: Int

<interactive>:6:1:
    No instance for (Fractional Int) arising from a use of ‘x’
    ...
Prelude> x :: Double
1.0

因为Int不是小数类型。

因此,Haskell的多态性是逆变的:限制为超类的多态值也可以被限制为子类,而不是相反。特别是,你显然可以

Prelude> let y = 1.0 :: Fractional a => a

yx'相同),但您无法将其概括为y' = 1.0 :: Num a => a。这是一件好事,因为Ingo说过,否则就有可能做到

Prelude> 3.14159 :: Int
  ????