Haskell 哈斯克尔';成对的s型

Haskell 哈斯克尔';成对的s型,haskell,types,ghci,Haskell,Types,Ghci,我想了解哈斯克尔的类型系统。我的想法如下: *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)的类型不像其他类型那样表示。我希望它是(“

我想了解哈斯克尔的类型系统。我的想法如下:

*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)


我以前已经看过
=>
。我想知道的是,为什么会有这种不同呢?

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

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


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

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

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


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

Num
是一个类型类。类型类有点像(但不是真的)OO接口。不同类型实现typeclass的功能,允许多态性

例如,有一个标准的
Eq
类,其定义为(您可以在ghci中使用
:info Eq

这意味着您可以编写类似于
isMember::(Eq a)=>a->[a]->Bool的函数。此函数获取实现(有一个实例)
Eq
的类型
a
和同一类型的列表,并返回布尔值。此泛型类型签名意味着您可以

elem 'c' "abcd"
elem 4 [1,2,3]
它会编译,但你不能这么做

elem 'c' [1,2,3]
现在,回到你原来的问题。 当您在ghci中键入数字时,它会尝试为该数字提供最通用的类型。它不知道
5
Int
,还是
Integer
,甚至是
Double
。因此,文本具有类型
(Num t)=>t
,这意味着“这个东西可以具有任何类型
t
,而不是实现
Num
typeclass”)

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


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

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

例如,有一个标准的
Eq
类,其定义为(您可以在ghci中使用
:info Eq

这意味着您可以编写类似于
isMember::(Eq a)=>a->[a]->Bool
的函数。此函数采用
a
类型的某个函数,该函数实现(有一个实例)Eq
和同一类型的列表,并返回一个布尔值。此通用类型签名意味着您可以这样做

elem 'c' "abcd"
elem 4 [1,2,3]
它会编译,但你不能这么做

elem 'c' [1,2,3]
现在,回到你原来的问题。 当您在ghci中键入一个数字时,它会尝试为该数字提供最通用的类型。它不知道
5
Int
,还是
Integer
,甚至是
Double
。因此,文本的类型为
(Num t)=>t,这意味着这个东西可以有任何类型
t
,而不是实现
Num
typeclass)

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


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

数字文字是一种特殊情况,
4
可以解释为
Int
整数,编译器不会为您做出选择,而是采用一种“最小公分母”以通用typeclass
Num
的形式(如其他答案所述)

我想说的另一点是,如果你在这一点上说得更具体一些,这种奇怪就会消失:

-- specify Int explicitly 
*Main> :t ("Hello", 4 :: Int)
("Hello", 4 :: Int) :: ([Char], Int)

-- specify Integer explicitly 
*Main> :t ("Hello", 4 :: Integer)
("Hello", 4 :: Integer) :: ([Char], Integer)

-- use an Int result from an expression
*Main> :t ("Hello", length [1,2,3])
("Hello", length [1,2,3]) :: ([Char], Int)

数字文字是一种特殊情况,
4
可以解释为
Int
整数
,编译器不会为您做出选择,而是以公共类型类
Num
的形式采用一种“最小公分母”(如其他答案所示)