有人可以解释为什么这会编译
Prelude> 1 :: Num a => a
这并不是
Prelude> 1.0 :: Num a => a
第二个示例适用于Fractional
,但Num
是Fractional
的超类。就像它的Integral
的超类一样。
答案 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 {...}
即。 A
是B
的超类,然后类型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
(y
与x'
相同),但您无法将其概括为y' = 1.0 :: Num a => a
。这是一件好事,因为Ingo说过,否则就有可能做到
Prelude> 3.14159 :: Int
????