如果我要创建一个函数,让我们举一个最简单的例子:
add x y = x + y
如果我想在之前添加函数类型声明,为了清晰起见
add :: (Int, Int) -> Int
add x y = x + y
我得到一个编译错误:
"无法匹配预期类型' Int '与实际类型' (Int, Int) ->(Int, Int)"。
" add的方程有两个参数,但它的类型是' (Int, Int) ->Int '只有一个">
但是如果我把它更正为
,它就可以完美地编译add :: (Int, Int) -> Int
add (x, y) = x + y
来自其他语言,我实际上认为使用第二种形式的括号更清楚,但在我看来,两种方式都应该工作
1 -不按第一种方式工作的原因是什么?
2 -我发现错误信息完全令人困惑,所以,也许,错误发生的另一个原因,我不理解
不按第一种方式工作的原因是什么?
在第一个表达式中,您的类型表示它接受一个2元组作为单个参数,并返回两个项的和。而是在"身体"里对于函数,您指定了add x y = x + y
,因此您构建了一个函数,该函数接受参数x
,该函数将返回一个函数,该函数接受参数y
,该参数映射到x + y
。
在Haskell中,所有函数都接受一个参数。实际上,您的add
函数接受一个参数x
。它是
add x = y -> x + y
因此,返回一个函数,该函数接受形参y
,然后将y
映射到x + y
。如果这样构造函数f = add 2
,则f
将接受参数y
,并将其映射到2 + y
上。
箭头是右结合运算符。这意味着Int -> Int -> Int
是Int -> (Int -> Int)
的缩写,因此它是一个将Int
映射到另一个函数的函数。
你可以看到像Java这样的语言的语法,它们调用f (x, y)
基本上是用一个对象调用函数f
:一个以x
和y
为两个元素的二元组。