Már*_*ldi 2 lambda haskell higher-order-functions
由于Haskell函数只有一个参数,其余参数保持为lambdas,那么我们可以这样做:
foo a b = a + b -- this is like foo a = \b -> a + b
foo 1 2 -- ok
Run Code Online (Sandbox Code Playgroud)
好吧,我注意到如果我声明函数返回一个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'
Run Code Online (Sandbox Code Playgroud)
...这会返回错误.
好的,问题是:为什么不从功能组合中返回lambda函数组合?我的意思是,在构图中我需要在括号周围加上括号,当从函数返回lambda时不需要括号.
我们假设你在GHCi中定义了以下内容:
?> let foo a b = a + b
?> let bar x = x * x
Run Code Online (Sandbox Code Playgroud)
bar . foo 1 2
Run Code Online (Sandbox Code Playgroud)
相当于
(bar . foo 1) 2
Run Code Online (Sandbox Code Playgroud)
但是,请记住函数应用程序(空间)的优先级高于组合运算符(.); 因此
bar . foo 1 2
Run Code Online (Sandbox Code Playgroud)
真的相当于
bar . ((foo 1) 2)
Run Code Online (Sandbox Code Playgroud)
现在,让我们来看看类型:
.有类型(b -> c) -> (a -> b) -> a -> c; 它的两个参数是函数(可以组成).bar具有类型Num a => a -> a,因此与b -> c第一个参数的type()兼容..foo 1 2有类型Num a => a; 它是一个(多态)数字常量,而不是函数,因此与第二个参数的type()不兼容.a -> b.这就是为什么你会遇到类型错误的原因bar . foo 1 2.但是你可以做的是
bar $ foo 1 2
Run Code Online (Sandbox Code Playgroud)
因为$运营商有类型(a -> b) -> a -> b.见Haskell:之间的区别.(点)和$(美元符号)
bar . foo 1 2是bar . (foo 1 2)不是(bar . foo 1) 2
这里没有什么神秘的事情与lambdas有关.假设我们将应用程序扩展foo为1:
bar . foo 1 2
bar . (\b -> 1 + b) 2
Run Code Online (Sandbox Code Playgroud)
现在,我们将lambda应用于2
bar . 3
Run Code Online (Sandbox Code Playgroud)
而且有你的问题.
相反,如果我们正确地放置括号,我们会像这样评估它:
(bar . foo 1) 2
(bar . (\b -> 1 + b)) 2
(\x -> bar ((\b -> 1 + b) x)) 2
bar 3
Run Code Online (Sandbox Code Playgroud)