http://pointfree.io gives a meaningless version of \abc -> a + b + c as ((+) .) . (+) ((+) .) . (+) .
Unofficially, composition only works “intuitively” for first-order functions that do not accept functions as arguments and do not return functions as values. (+) - higher order function; it takes a value of type Num a => a and returns a function of type Num a => a -> a . When you try to compose higher-order functions in a naive way, the result is not what you expect:
:t (+) . (+) (+) . (+) :: (Num a, Num (a -> a)) => a -> (a -> a) -> a -> a
Consider the definitions of two functions:
(+) :: Num z => z -> z -> z (.) :: (b -> c) -> (a -> b) -> (a -> c) f . g = \x -> f (gx)
Then
(+) . (+) == (.) (+) (+) == \x -> (+) ((+) x)
Because of currying, you end up passing the function, not the number, like the first argument of the first (+) .
So, how do we get from habc = a + b + c to h = ((+) .) . (+) h = ((+) .) . (+) ? Start by rewriting the infix expression as a prefix expression, using the fact that (+) left associative.
\abc -> a + b + c == \abc -> ((+) ab ) + c == \abc -> (+) ((+) ab) c
Then we alternately apply the eta transform to exclude the argument and composition in order to move the argument to a position that needs to be eliminated. I tried to very clearly define the functions used to apply the composition.
== \ab -> (+) ((+) ab) -- eta conversion to eliminate c == \ab -> (+) (((+) a) b) -- parentheses justified by currying -- fg -- f = (+), g = ((+) a) -- \ab -> f ( gb) -- \ab -> (f . g) b -- definition of (.) == \ab -> ((+) . ((+) a)) b == \a -> (+) . ((+) a) -- eta conversion to eliminate b == \a -> (.) (+) ((+) a) -- prefix notation == \a -> ((.) (+)) ((+) a) -- parentheses justified by currying == \a -> ((+) . )((+) a) -- back to a section of (.) -- fg -- f = ((+) .), g = (+) -- \a -> f (ga) -- \a -> ( f . g) a -- definition of (.) == \a -> (((+) .) . (+)) a == ((+) .) . (+) -- eta conversion to eliminate a
source share