简体   繁体   中英

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

Considering Haskell has currying functions, we can do this:

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.

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:

λ> 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 ; 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 . .
  • foo 1 2 has type 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 . .

That's why you're getting a type error in 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 . See Haskell: difference between . (dot) and $ (dollar sign)

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

There's nothing mysterious going on here related to lambdas. Say we expanded the application of foo to 1:

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

Now, we apply the lambda to the 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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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