2017-02-11 59 views
0

可能有人请解释为什么这编译设置类型为NUM

Prelude> 1 :: Num a => a 

这并不

Prelude> 1.0 :: Num a => a 

第二个例子将与Fractional工作,但NumFractional超。就像它的超类Integral

回答

4

如果我们有

x :: Num a => a 

x用户可以选择a通缉。例如。

x :: Int 

如果x = 1.5不适用?

因为这个原因浮点文字不能给多态类型Num a => a,因为它的值不会(通常)适合所有类型的所有Num

积分文字适合每种数字类型,因此它们是允许的。

+0

谢谢@chi。当你这样做时有意义:)所以'1 :: Num a => a'适用于任何'Num'实例的'a',但'1.0'不适用。 – rodic

+1

@rodic是的。从理论上讲,Haskell的设计者可能已经强制要求'1.0'被当作'1'来处理,但实际上,发现在给定的上下文中'1.0'类型检查但是'1.5'确实会引起混乱不。因此,只允许使用'1.0'来代表'Fractional'类型中的类型值。 – chi

+0

是的,当我写1.0时,我有任何想法。但现在我意识到我的原始问题可以重写,为什么'1 :: a'不能编译。非常感谢您的帮助。 – rodic

3

类型类之间的超类关系确实是而不是在类型之间建立关系。它告诉我们,只有,如果类型T是类型类Ç的一员,并是一个超类的Ç,然后也将的成员。

说每个值v ::吨可以在任何类型的,这也是的构件使用。但这就是你要说的:

3.14159 :: Num a => a 
3

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

这意味着:在面向对象的语言,如果你有

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类型可能在Num类。

不像在面向对象的语言,如1 :: Num a => a多态:它可以在任何类型的环境的需求,提供的类型在Num类。 (其实这句法只是缩写1 :: ∀ a . Num a => a,将被解读为“为所有类型的a,你可以有a类型的值1。)例如,

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 
    ???? 
+0

明白了。 num不是类似于oo的类型,而是一组类型,为了val是多态的,它必须能够实例化为任何num类型,任何其他规则都会导致荒谬的情况,正如你们所展示的那样。 – rodic