Haskell 高阶函数和圆括号

Haskell 高阶函数和圆括号,haskell,Haskell,根据compose在的类型,它可以写成 compose::[a->a]->(a->a) 或compose::[a->a]->a->a 我认为这两种类型是不同的:前者获取函数列表并返回函数,后者获取函数列表和参数,然后最终返回值 也就是说,当一个函数(高阶函数)将另一个函数作为参数或返回一个函数作为结果时,不应忽略参数(结果)周围的括号,例如,如果filter::(a->Bool)->[a]->[a]删除括号,其含义将发生变化 我是对的还是错的?这两者都是一样的: compose1 :: [a -

根据compose在的类型,它可以写成
compose::[a->a]->(a->a)
compose::[a->a]->a->a

我认为这两种类型是不同的:前者获取函数列表并返回函数,后者获取函数列表和参数,然后最终返回值

也就是说,当一个函数(高阶函数)将另一个函数作为参数或返回一个函数作为结果时,不应忽略参数(结果)周围的括号,例如,如果
filter::(a->Bool)->[a]->[a]
删除括号,其含义将发生变化


我是对的还是错的?

这两者都是一样的:

compose1 :: [a -> a] -> (a -> a)
compose1 [] = \x -> x
compose1 [f] = \x -> f x
compose1 (f1:f2:fs) = compose1 ((f2 . f1):fs)

compose2 :: [a -> a] -> a -> a
compose2 [] x = x
compose2 [f] x = f x
compose2 (f1:f2:fs) x = compose2 ((f2 . f1):fs) x
请注意,这些定义实际上是完全相同的,只是lambda从
=
的一侧移到了另一侧。实际上,您始终可以执行以下转换:

f x y z = <expr x y z>
f x y = \z -> <expr x y z>
f x = \y -> \z -> <expr x y z> = \y z -> <expr x y z>
f = \x -> \y -> \z -> <expr x y z> = \x y z -> <expr x y z>
相当于

f = \x -> <expr>
-- Not equivalent!
f :: (((a -> b) -> c) -> d) -> e
这就是向右关联的意思,添加嵌套括号时从右向左。但是,
f
的签名不等于

f = \x -> <expr>
-- Not equivalent!
f :: (((a -> b) -> c) -> d) -> e
这仅仅是因为
->
不是完全关联运算符。例如,使用
+
可以

x + (y + z) = (x + y) + z
x -> (y -> z) /= (x -> y) -> z
但是有了
->
你就有了

x + (y + z) = (x + y) + z
x -> (y -> z) /= (x -> y) -> z
这类似于
运算符,例如

1:2:3:4:[] == 1:(2:(3:(4:[])))
           /= (((1:2):3):4):[]

最后一个表达式不会进行类型检查,因为
1:2
类型错误,
2
不是列表

箭头是右关联的,因此
[a->a]->a
[a->a]->(a->a)
是等效的

如果删除
过滤器
的类型签名中的括号,则会得到:

a -> Bool -> [a] -> [a]
a -> Bool -> ([a] -> [a])
a -> (Bool -> ([a] -> [a]))

。。。这与正确的类型签名不同。

不是专家,但我认为这两种情况是相同的。这是因为curry()如果只给curry
compose
第一个参数,例如函数列表,那么每种情况下的结果类型是什么?这有助于解释发生了什么吗?在这两种情况下,在curry之后,如果您只提供一个参数(type
a
),会发生什么?我鼓励您思考您希望能够进行哪些观察来区分这两种类型,并尝试在ghci中进行这些观察。他们不同吗?(我以这种方式鼓励你,因为当我了解这个空间发生的事情时,我的思想爆炸了,从此我就无法离开哈斯克尔。)你错了-
->
是正确的,所以
a->foodiebar
自动变成
(>)(foodiebar)
。这对于函数也是一样的:
a->b->c
a->(b->c)