When you go to a point, this can be confusing. If we go through type signatures,
(.) (b -> c) -> (a -> b) -> a -> c
(+) Num a => a -> a -> a
(2*) Num a => a -> a
Now if we do (2*) . (+) (2*) . (+) second parameter (.) , which is (+) , should be of type (a -> b) , which is really true when we rewrite (+) type as Num a => a -> (a -> a) Therefore, our b type is Num a => a -> a . Now remember that (.) Takes (b -> c) as the first parameter. We have a little problem here, because in our expression (2*) . (+) (2*) . (+) (2*) waiting for type b type Num a => a , while we have our type b , for example Num a => a -> a . You cannot multiply a function by 2 ..! We need to convert (2*) to a function that takes a function of our type, which Num a => a -> a , starts it and feeds the result to (2*) . There is no need to watch it no more (.) . In this case, if we write again as ((2*) . ) , We can safely pass our function like Num a => a -> a (remember that this is partially applied (+) ). Let's finish it ...
Our point free equivalent \xy -> 2*(x + y) is ((2*) . ) . (+) ((2*) . ) . (+)
Prelude> (((2*) . ) . (+)) 3 5 16
We can use applicative functors like ((->) r) to make it easier to express ourselves in these situations. I will try to add it as soon as I have more time.
source share