仍然混淆带有多个箭头的类型签名是如何工作的
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]
:一个函数采用 a
和 b
以及 returning b
、b
和 a
的列表。
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]
是“三个参数”的类型。但严格来说,这是错误的。
我之前查了一个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]
:一个函数采用 a
和 b
以及 returning b
、b
和 a
的列表。
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]
是“三个参数”的类型。但严格来说,这是错误的。