2

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?

Mário Feroldi
  • 3,463
  • 2
  • 24
  • 49
  • 1
    Erm, _what_ error? We don't know what the error is! Put it here. – AJF Dec 18 '14 at 13:06
  • 1
    "No instance for (Show (a0 -> c0)) arising from a use of ‘print’". Actually, it's not really an error. I'm saying that using `bar . foo 1 2` doesn't work as I want to. – Mário Feroldi Dec 18 '14 at 13:08
  • But the composition operator gets only two arguments and returns a lambda, ok? Why doesn't it work as a normal function? – Mário Feroldi Dec 18 '14 at 13:11
  • 1
    *Why doesn't returning a lambda from function work like the function composition? I mean, in composition I need to put parentheses around the one, and no parentheses are needed when a lambda is returned from function.* What you're asking is unclear... Which *function* are you referring to? – jub0bs Dec 18 '14 at 13:13
  • 1
    @Thelost A lambda _IS_ a normal function! There's no difference at all. – AJF Dec 18 '14 at 13:14
  • You're probably confusing the function composition operator with `$`: `bar $ foo 1 2` works fine. – jub0bs Dec 18 '14 at 13:22
  • No. I'm sure what I'm saying. – Mário Feroldi Dec 18 '14 at 13:32
  • related: http://stackoverflow.com/questions/940382/haskell-difference-between-dot-and-dollar-sign – jub0bs Sep 08 '15 at 07:48

2 Answers2

8

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. 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)

Community
  • 1
  • 1
jub0bs
  • 60,866
  • 25
  • 183
  • 186
  • @Thelost Just to be clear: are you asking why `(bar . foo 1) 2` does work whereas `bar . foo 1 2` doesn't? Note that, if you define `foo a = \b -> a + b`, then `bar . foo 1 2` still doesn't work... – jub0bs Dec 18 '14 at 13:38
  • Exactly! This is my question. Looking to the Haskell's rules, Functions can receive only one argument. Then, I thought that the Haskell looks for this: `bar . foo 1 2` and says that the foo is receiving the 1, and returning a lambda. Therefore, the composition happens here: `bar . foo 1` and let the `2` out of this. – Mário Feroldi Dec 18 '14 at 13:46
  • 3
    @Thelost No. `bar . foo 1 2` is equivalent to `bar . ((foo 1) 2)`, *not*, as you seem to think, to `(bar . foo 1) 2`. Function application (space) has the higher precedence, so what gets passed as the second argument to `.` is the value of `foo 1 2`. – jub0bs Dec 18 '14 at 13:48
6

bar . foo 1 2 is 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
Sarah
  • 6,565
  • 1
  • 33
  • 44