为什么Haskell在函数组合后不接受参数?

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时不需要括号.

jub*_*0bs 8

我们假设你在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:之间的区别.(点)和$(美元符号)

  • @Thelost No.`bar.foo 1 2`相当于`bar.((foo 1)2)`,*not*,如你所想,对`(bar.foo 1)2`.函数应用程序(空格)具有更高的优先级,因此作为第二个参数传递给`.`的是`foo 1 2`的值. (3认同)

Sar*_*rah 6

bar . foo 1 2bar . (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)

  • @AJFarmar我试着让它更清楚,为什么这不是问题. (4认同)