简体   繁体   English

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

[英]Why doesn't Haskell accept arguments after a function composition?

Considering Haskell has currying functions, we can do this:考虑到 Haskell 有柯里化功能,我们可以这样做:

foo a b = a + b -- equivalent to `foo a = \b -> a + b`

foo 1 -- ok, returns `\b -> 1 + b`
foo 1 2 -- ok, returns 3

Declaring the function returning a lambda, just like in the comment, works just fine as well.声明返回 lambda 的函数,就像在注释中一样,也可以正常工作。

But when I compose these functions, like this:但是当我组合这些函数时,就像这样:

foo a b = a + b
bar x = x * x

bar . foo 1 -- ok, returns a lambda
bar . foo 1 2 -- wrong, I need to write `(bar . foo 1) 2`

Then it results in an error.然后它会导致错误。

The question is: why are the parentheses around the function composition necessary?问题是:为什么函数组合周围的括号是必要的?

Let's assume that you've define the following in GHCi:假设您已经在 GHCi 中定义了以下内容:

λ> let foo a b = a + b
λ> let bar x = x * x

Based on some of your follow-up comments , it seems that you believe根据您的一些后续评论,您似乎相信

bar . foo 1 2

to be equivalent to相当于

(bar . foo 1) 2

However, remember that function application (space) has higher precedence than the composition operator ( . );但是,请记住,函数应用程序(空格)的优先级高于组合运算符( . ); therefore所以

bar . foo 1 2

is really equivalent to真的相当于

bar . ((foo 1) 2)

Now, let's look at the types:现在,让我们看看这些类型:

  • . has type (b -> c) -> (a -> b) -> a -> c ;有类型(b -> c) -> (a -> b) -> a -> c ; its two arguments are functions (that can be composed).它的两个参数是函数(可以组合)。
  • bar has type Num a => a -> a , and is therefore compatible with the type ( b -> c ) of the first argument of . bar类型为Num a => a -> a ,因此与 的第一个参数的类型 ( b -> c ) 兼容. . .
  • foo 1 2 has type Num a => a ; foo 1 2类型为Num a => a it's a (polymorphic) numeric constant, not a function, and is therefore not compatible with the type ( a -> b ) of the second argument of .它是一个(多晶型)的数字常数,而非函数,并且因此与类型兼容( a -> b的第二个参数的) . . .

That's why you're getting a type error in bar . foo 1 2这就是您在bar . foo 1 2收到类型错误的原因bar . foo 1 2 bar . foo 1 2 . bar . foo 1 2 What you can do, though, is不过,你可以做的是

bar $ foo 1 2

because the $ operator has type (a -> b) -> a -> b .因为$运算符的类型为(a -> b) -> a -> b See Haskell: difference between .请参阅Haskell: . (dot) and $ (dollar sign) (点)和 $(美元符号)

bar . foo 1 2 bar . foo 1 2 is bar . (foo 1 2) bar . foo 1 2bar . (foo 1 2) bar . (foo 1 2) not (bar . foo 1) 2 bar . (foo 1 2)不是(bar . foo 1) 2

There's nothing mysterious going on here related to lambdas.这里没有任何与 lambda 相关的神秘事情。 Say we expanded the application of foo to 1:假设我们将foo的应用扩展为 1:

bar . foo 1 2
bar . (\b -> 1 + b) 2

Now, we apply the lambda to the 2现在,我们将 lambda 应用于 2

bar . 3

And there is your problem.这就是你的问题。

Conversely, if we place the parentheses correctly, we evaluate it like this:相反,如果我们正确放置括号,我们会像这样评估它:

(bar . foo 1) 2
(bar . (\b -> 1 + b)) 2
(\x -> bar ((\b -> 1 + b) x)) 2
bar 3

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM