Haskell Functional composition error

204 views Asked by At

I might be asking something very stupid and the answer might be very simple as "the implementor chose it that way", but here I go.

To add two numbers we can use any style: (10+) 4 or 10 + 4 or (10 + 4).

while if we have two functions, say add10 and multiply5 and compose them to make one function out of it, say add10andMultiply5 then
add10.mul5 10 seems to give an error while
add10.mul5 $ 5 will work and
(add10.mul5) 5 will work and
add10andMultiply5 5 will also work.

Any comments why the first one should not work ? Please enlighten me. Thanks.

2

There are 2 answers

0
Impredicative On BEST ANSWER

Functional composition in Haskell has lower precedence than function application. So add10.mul5 10 is parsed as add10 . (mul5 10). Now, the type of . is given as:

(.) :: (b -> c) -> (a -> b) -> a -> c

The first argument (add10) has type Int -> Int, so we can establish that b is Int, and hence . expects its second argument to be of type a -> Int. But instead it's of type Int. Adding the $ changes the association, and means that instead the function composition is done before applying the composed function to 10.

Everything works in your first example because you're not composing functions, you're just applying them. The equivalent in this case would be trying to do (10+) . 4, which you will observe also fails.

0
Chris Taylor On

It's an issue of precedence, or how tightly different operations bind.

In Haskell, function application has the highest precedence (tightest binding), followed by function composition, followed by function application with $. It's a bit like arithmetic, where exponentiation has highest precedence, then multiplication, then addition, so that

1 + 2 ^ 4 * 3 + 4 * 3

is parsed as

1 + ((2 ^ 4) * 3) + (4 * 3)

In your examples, you have

add10 . mul5 10

which will be parsed as

add10 . (mul5 10)

because the function application binds tightest. This doesn't work, because mul5 10 is a number and add10 is a function, and composition only works between two functions.

On the other hand,

add10 . mul5 $ 10

is parsed as

(add10 . mul5) $ 10

because function composition has higher precedence then application with $.