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

Still confuse how type signature with multiple arrows work

我之前查了一个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]是输入输出吗?那中间剩下的是什么?

从函数可以有多个参数的更常见的角度来思考这一点,签名中的最后一个类型是 return 类型。前面的都是参数的类型。

在此示例中,您的参数类型为 (a -> b -> b)b[a]:一个函数采用 ab 以及 returning bba 的列表。

return类型是签名中的最后一个类型[b]b的列表。

读取类型签名作为转换 ... -> to,其中 "rest in the middle" 是参数。

例如。 myscanr :: (a -> b -> b) -> b -> [a] -> [b] "takes" 一个函数 (a -> b -> b),一个 b,一个列表 a [a] 和 returns 你一个列表 b [b]

从概念上讲,Haskell 中的函数总是只有一个 参数。确实,其实签名:

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

是以下简称:

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

所以总是有一个参数,但结果也可以是函数,然后我们可以为该函数获取一个值或另一个结果,所以这是某种 "chaining".

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

# python

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

所以这里我们有一个函数add。我们可以用一个参数 x 来调用它。如果我们这样做,例如 x=4,那么它将 return 另一个函数(其中 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 为函数和 (+) 为参数的函数调用,另一个函数调用以 as function 为前一个调用的结果和 0 作为参数,然后另一个函数调用以 as function 为前一个调用的结果以 [1, 4, 2, 5] 作为参数。

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