仍然混淆多个箭头的类型签名是如何工作的

时间:2018-06-12 20:03:23

标签: haskell currying type-signature

我之前检查过post并且似​​乎明白了。我知道

f :: a -> b -> c 

的咖喱形式
g :: (a, b) -> c

但是由于类型签名比2个箭头长,我感到很困惑。

myscanr :: (a -> b -> b) -> b -> [a] -> [b]
myscanr op z [] = [z]
myscanr op z (x:xs) = op x (head qs) : qs
  where
    qs = myscanr op z xs

输入和输出是(a -> b -> b)[b]吗?那么中间的其余部分是什么?

3 个答案:

答案 0 :(得分:11)

从概念上讲,Haskell中的函数始终只有一个参数。事实上,实际上是签名:

myscanr :: (a ->  b -> b ) ->  b ->  [a] -> [b]

简称:

myscanr :: (a -> (b -> b)) -> (b -> ([a] -> [b]))

所以总有一个参数,但结果也可以是函数,然后我们可以为该函数提供一个参数来获取一个值,或者另一个结果,所以这是某种"链接"。

您可以将它与Python之类的编程语言进行比较,而不是拥有一个接受多个参数的函数,它每次都接受一个参数。例如:

# python

def add(x):
    def addx(y):
        return x + y
    return addx

所以这里我们有一个函数add。我们可以使用单个参数x来调用它。如果我们这样做,例如x=4,那么它将返回另一个函数(其中x作用域)。只有当我们用一个参数(例如y=3)调用该函数时,我们才得到结果,如:

>>> add(4)
<function add.<locals>.addx at 0x7f1c519e7b70>
>>> add(4)(3)
7

在Haskell中,这个模型是标准:每个函数只接受一个参数。但既然如此,语法可以改进。我们可以编写((myscanr((+)))(0))([1, 4, 2, 5])而不必编写myscanr (+) 0 [1, 4, 2, 5],而Haskell会自动将其解释为函数调用,myscanr为函数,(+)为参数,另一个函数调用使用前一个调用的结果和0作为参数的函数,然后使用[1, 4, 2, 5]作为参数,使用as函数调用另一个函数调用。

从语法上讲,它看起来有点像我们使用三个参数进行调用,可以说(a -> b -> b)b[a]是&#34; 三个参数&#34;的类型。但严格来说,这是错误的。

答案 1 :(得分:5)

从更常见的视图中考虑这一点,其中函数可以有多个参数,签名中的最后一个类型是返回类型。之前的一切都是参数的类型。

在此示例中,您的参数类型为(a -> b -> b)b[a]:一个函数,其中包含ab并返回{ {1}},bb s。

列表

返回类型是签名a中的最后一种类型:[b]的列表。

答案 2 :(得分:4)

将类型签名读作转换... -> to,其中&#34;位于中间&#34;是争论。

例如。 myscanr :: (a -> b -> b) -> b -> [a] -> [b]&#34;&#34;功能(a -> b -> b)b[a]列表,并返回b [b]

列表