Haskell的Pairs类型

时间:2014-02-27 15:53:10

标签: haskell types ghci

我正在尝试理解Haskell的类型系统。我发现了以下内容:

*Main> :t ("Hello", 4)
("Hello", 4) :: Num t => ([Char], t)

*Main> :t ("Hello", 'a')
("Hello", 'a') :: ([Char], Char)

*Main> :t ("Hello", True)
("Hello", True) :: ([Char], Bool)

为什么("Hello", 4)的类型没有像其他类型那样表示。我原以为它是("Hello", 4) :: ([Char], Num)

之前我已经看过=>了。我想知道的是,为什么它会产生这种差异?

3 个答案:

答案 0 :(得分:11)

那是因为Num不是一个类型;它是typeclass,而Num t => someType表示t是某种任意类型,它是Num类型类的实例。借用一些Java / C#术语,您可以将Num视为接口,Num t => t是一种通用类型,其约束条件t必须实现Num接口。

通常,您会在=>箭头的左侧找到类型类约束,在右侧找到类型正文。我们可以有多个类约束,例如(Num a, Num b) => (a, b),它表示两个任意数字类型的元组的类型。我们也可以有零类约束,在这种情况下省略=>

在Haskell中,数字文字可以表示作为Num实例的任何类型。文字4可以表示浮点数或整数,或者(如果你定义一些更奇特的实例)甚至是函数。

答案 1 :(得分:2)

Num是一个类型类。类型类似于(但不是真的)类似于OO接口。不同的类型实现了类型类的功能,允许多态性。

例如,有一个标准Eq类,定义为(您可以使用:info Eq在ghci中获取此内容)

class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool

这意味着您可以编写isMember :: (Eq a) => a -> [a] -> Bool之类的函数。此函数采用类型a实现(具有实例)Eq和相同类型的列表,并返回布尔值。此通用类型签名意味着您可以执行

elem 'c' "abcd"
elem 4 [1,2,3]

它会编译,但你不能做

elem 'c' [1,2,3]

现在,回到原来的问题。 当您在ghci中键入数字时,它会尝试将该数字设为最常用的类型。它不知道5Int,还是Integer,甚至是Double。因此,文字具有类型(Num t) => t,这意味着“此事件可以具有任何类型t,而不是实现Num类型类别。”

不同的表达式会为您提供更具体的类型。例如,5 `div` 3的类型为(Integral a) => a,因为divIntegral类的方法。

如果您想了解有关类型类的更多信息,this是一个很好的链接。

答案 2 :(得分:2)

数字文字是一种特殊情况,4可以是例如解释为IntInteger,编译器不会为您做出选择,而是以公共类型类{{1}的形式采用一种“最小公分母” (正如其他答案已经解释过的那样)。

我试图提出的另一点是,如果你在这一点上更具体,那么古怪就会消失:

Num