高阶函数和括号

时间:2015-01-29 16:31:24

标签: haskell

根据https://wiki.haskell.org/Compose的撰写类型,可以写为
 compose :: [a -> a] -> (a -> a)compose :: [a -> a] -> a -> a

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

即,当函数(高阶函数)将另一个函数作为参数或作为结果返回函数时,参数(结果)周围的括号不应该被省略,例如,如果{{ 1}}删除括号,其含义会改变。

我是对还是错?

2 个答案:

答案 0 :(得分:7)

这些都是相同的:

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>

这实际上是编译器对所有函数的作用。如果使用-ddump-simpl进行编译,您将看到转储的核心代码,其中所有函数都是根据lambdas定义的。这是因为Haskell使用的法则

f x = <expr>

相当于

f = \x -> <expr>

lambda语法可以被认为是比使用显式参数定义函数更基本的语法。


  

即,当函数(高阶函数)将另一个函数作为参数或作为结果返回函数时,不应省略参数(结果)周围的括号,例如{{1}删除括号,其含义将改变。

您认为无法从filter :: (a -> Bool) -> [a] -> [a]的类型签名中删除括号,这是正确的,这是因为函数应用程序只是右关联。这意味着以下签名是等效的:

filter

这是通过关联到右边的意思,在添加嵌套括号时从右到左。但是,f :: a -> b -> c -> d -> e f :: a -> (b -> (c -> (d -> e))) 的签名 等同于

f

仅仅因为-- Not equivalent! f :: (((a -> b) -> c) -> d) -> e 不是完全关联的运算符。例如,->你有

+

但是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不是列表!

答案 1 :(得分:7)

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

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

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

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