Haskell LanguageFunction composition


Remarks

Function composition operator (.) is defined as

(.) :: (b -> c) -> (a -> b) ->  (a -> c)
(.)       f           g          x =  f (g x)     -- or, equivalently,  

(.)       f           g     =   \x -> f (g x)     
(.)       f     =    \g     ->  \x -> f (g x)      
(.) =    \f     ->   \g     ->  \x -> f (g x)      
(.) =    \f     ->  (\g     -> (\x -> f (g x) ) ) 

The type (b -> c) -> (a -> b) -> (a -> c) can be written as (b -> c) -> (a -> b) -> a -> c because the -> in type signatures "associates" to the right, corresponding to the function application associating to the left,

 f g x y z ...    ==    (((f g) x) y) z ...

So the "dataflow" is from the right to the left: x "goes" into g, whose result goes into f, producing the final result:

(.)       f           g          x =  r
                                      where r = f (g x)  
-- g :: a -> b
-- f ::      b -> c
-- x :: a      
-- r ::           c   

(.)       f           g     =    q
                                 where q = \x -> f (g x) 
-- g :: a -> b
-- f ::      b -> c
-- q :: a      -> c

....

Syntactically, the following are all the same:

(.) f g x  =  (f . g) x  =  (f .) g x  =  (. g) f x 

which is easy to grasp as the "three rules of operator sections", where the "missing argument" just goes into the empty slot near the operator:

(.) f g    =  (f . g)    =  (f .) g    =  (. g) f   
--         1             2             3  

The x, being present on both sides of the equation, can be omitted. This is known as eta-contraction. Thus, the simple way to write down the definition for function composition is just

(f . g) x   =   f (g x)

This of course refers to the "argument" x; whenever we write just (f . g) without the x it is known as point-free style.