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

use*_*628 3 haskell currying type-signature

我之前检查了一个帖子,似乎明白了.我知道

f :: a -> b -> c 
Run Code Online (Sandbox Code Playgroud)

是咖喱的形式

g :: (a, b) -> c
Run Code Online (Sandbox Code Playgroud)

但由于类型签名长于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
Run Code Online (Sandbox Code Playgroud)

(a -> b -> b)[b]输入和输出?那么中间剩下的是什么?

Wil*_*sem 11

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

myscanr :: (a ->  b -> b ) ->  b ->  [a] -> [b]
Run Code Online (Sandbox Code Playgroud)

是短的:

myscanr :: (a -> (b -> b)) -> (b -> ([a] -> [b]))
Run Code Online (Sandbox Code Playgroud)

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

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

# python

def add(x):
    def addx(y):
        return x + y
    return addx
Run Code Online (Sandbox Code Playgroud)

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

>>> add(4)
<function add.<locals>.addx at 0x7f1c519e7b70>
>>> add(4)(3)
7
Run Code Online (Sandbox Code Playgroud)

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

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


Car*_*ate 5

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

在此示例中,您的参数类型是(a -> b -> b),b[a]:一个函数接受a a和a b并返回a b,a bas 列表.

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