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

时间:2014-12-18 13:01:18

标签: haskell lambda higher-order-functions

由于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时不需要括号。

2 个答案:

答案 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
相关问题