理解Haskell类型签名(例如zipWith with(+;))

理解Haskell类型签名(例如zipWith with(+;)),haskell,signature,type-signature,Haskell,Signature,Type Signature,我有一个关于Haskell中的类型签名的问题,我发现有时候有点难以理解。例如,zipWith的类型签名为: zipWith :: (a -> b -> c) -> [a] -> [b] -> [c] 我在这里看到的是zipWith需要一个函数(参数类型为a和b),一个带有as的列表,一个带有bs的列表,它给我们一个cs的列表。但是我不明白为什么我可以将zipWith与(+)一起使用,例如,它有以下签名: (+) :: a -> a -> a zipW

我有一个关于Haskell中的类型签名的问题,我发现有时候有点难以理解。例如,
zipWith
的类型签名为:

zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
我在这里看到的是
zipWith
需要一个函数(参数类型为
a
b
),一个带有
a
s的列表,一个带有
b
s的列表,它给我们一个
c
s的列表。但是我不明白为什么我可以将
zipWith
(+)
一起使用,例如,它有以下签名:

(+) :: a -> a -> a
zipWith' :: (a -> a -> a) -> [a] -> [a] -> [a]
在我看来,
(+)
的签名与
(a->b->c)
的签名不匹配<代码>(+)只需要类型
a
的参数,而
(a->b->c)
需要不同类型的参数:
a
b
。谁能给我一个提示,我的错在哪里?

(a->b->c)
表示任何函数,它接受类型
a
和类型
b
,并返回类型
c
。 没有什么可以阻止您使用签名为
(a->a->a)
的函数,只是在这种情况下,类型都是相同的

假设您有一个具有此签名的方法:

(+) :: a -> a -> a
zipWith' :: (a -> a -> a) -> [a] -> [a] -> [a]

在这种情况下,您不能使用签名为
(a->b->c)
的方法,因为预期的方法签名更严格。

啊,我明白了。因此,当我在函数签名中使用不同的类型参数时,所有类型都可以是相同的。但是在类型签名中,如(a->a->a)1。参数必须具有与2相同的类型。参数,对吗?你的第一句话有点误导;对于
(对于所有a b c.(a->b->c))
,这是正确的,但该类型不会出现在带有
签名的
Zipw中。@Meiner-正确。换句话说,
a->a->a
a->b->c
的一个特殊实例,其中
b
恰好与
a
相同,
c
。这个过程的术语是统一。这个术语实际上更一般;在类型推断的上下文中,这就是为什么
a
可以匹配
Int
,或者
[a]->b
可以匹配
[Bool]->[Char]->[Int->Int]
。另一种看待
zipWith
函数的方法是它“提升”由于签名可以写成
zipWith::(a->b->c)->([a]->[b]->[c])
,因此列表monad有两个参数的函数。在
(+)::Int->Int->Int
a~Int
b~Int
c~Int
的情况下,因此
zipWith(+)::[Int]->[Int]->[Int]