为什么Haskell使用箭头作为函数的类型?

时间:2014-11-16 20:21:42

标签: haskell syntax

我刚开始学习Haskell,其中一个奇怪的事情就是具有多个参数的函数类型的语法。

考虑一个简单的例子:

(+) :: Num a => a -> a -> a

为什么我们需要这里的所有箭头?写Num Num Num -> Num之类的东西会不会更有意义?

引擎盖下的原因是什么?我搜索了这个问题,但找不到任何真正有用的东西。

2 个答案:

答案 0 :(得分:18)

令人困惑的第一件事是Num a =>,所以我们现在完全忽略这一点。相反,我们考虑Int -> Int -> Int,这是您提供的类型签名的一种可能的专业化。

Haskell中的函数几乎总是curried。这意味着多参数函数实际上是一个参数的函数,它返回一个接受下一个参数的函数,依此类推。

->是关联的,因此Int -> Int -> IntInt -> (Int -> Int)相同。

这也意味着这个定义

f :: Int -> Int -> Int
f x y = x + y

相同
f :: Int -> Int -> Int
f x = \y -> x + y

实际上,Haskell中的所有函数都只使用一个参数。元组也存在,但它们是一等公民,因此它们不仅仅是一个参数列表。

Num a =>是类型系统的一个不同方面。它表示类型变量a必须是Num类型类的实例。作为Num实例的类型的常见示例包括IntDouble。所以Num本身不是一个类型,它是一个类型类。 Num a =>表示对类型变量a的约束,它不是该函数的另一个参数。

(+)方法是Num类型类的成员,因此您必须以这种方式约束a才能使用(+)。如果您尝试为f提供签名a -> a -> a(没有约束),它将无效,因为a完全不受约束,我们对它的类型一无所知。因此,我们无法在其上使用(+)

答案 1 :(得分:0)

函数类型签名中每个参数的类型可以包含空格,因此非常需要非空白分隔符,因此编译器(和人类!)可以区分它们。

例如,您可以使用参数化抽象数据类型:

data MyType a = MyValue a

和一个采用具体类型的函数(由MyType类型构造函数构造):

myFunc :: MyType Int -> MyType Int -> String

如果您在参数之间没有->,则签名看起来像

myFunc :: MyType Int MyType Int -> String   -- Not valid code

并且编译器在计算函数的实际参数意图时会遇到更多麻烦(我想知道在某些情况下它甚至可能是不可能的吗?)。至少,它不太容易理解。