由于Haskell函数只有一个参数,其余参数保持为lambdas,那么我们可以这样做:
foo a b = a + b -- this is like foo a = \b -> a + b
foo 1 2 -- ok
好吧,我注意到如果我声明函数返回一个lambda,就像在注释中一样,foo 1 2
将以同样的方式工作。
但是当我编写这些函数时,就像这样:
foo a b = a + b
bar x = x * x
bar . foo 1 2 -- oh, it's wrong, I need do '(bar . foo 1) 2'
...这会返回错误。
好的,问题是:为什么不从函数组合中返回lambda函数组合?我的意思是,在构图中我需要在括号中加上括号,当从函数返回lambda时不需要括号。
答案 0 :(得分:8)
我们假设您在GHCi中定义了以下内容:
λ> let foo a b = a + b
λ> let bar x = x * x
基于某些your follow-up comments,您似乎相信
bar . foo 1 2
等同于
(bar . foo 1) 2
但是,请记住,函数应用程序(空格)的优先级高于组合运算符(.
);因此
bar . foo 1 2
实际上相当于
bar . ((foo 1) 2)
现在,让我们看一下类型:
.
的类型为(b -> c) -> (a -> b) -> a -> c
;它的两个参数是函数(可以组成)。bar
的类型为Num a => a -> a
,因此与b -> c
的第一个参数的类型(.
)兼容。foo 1 2
的类型为Num a => a
;它是一个(多态)数字常量,不是一个函数,因此不与{的第二个参数的类型(a -> b
)兼容{1}}。这就是您在.
中收到类型错误的原因。但是你可以做的是
bar . foo 1 2
因为bar $ foo 1 2
运算符的类型为$
。见Haskell: difference between . (dot) and $ (dollar sign)
答案 1 :(得分:6)
bar . foo 1 2
bar . (foo 1 2)
不是(bar . foo 1) 2
这里没有任何与lambdas相关的神秘事物。假设我们将foo
的应用扩展为1:
bar . foo 1 2
bar . (\b -> 1 + b) 2
现在,我们将lambda应用于2
bar . 3
还有你的问题。
相反,如果我们正确地放置括号,我们会这样评估:
(bar . foo 1) 2
(bar . (\b -> 1 + b)) 2
(\x -> bar ((\b -> 1 + b) x)) 2
bar 3