Search code examples
haskellmathghcicalculus

Haskell - How to write (.) f f = (\x -> f (f x))


I need to write on a module to be run on GHCi, with a function composition to the same function. This (The classic fog(x) = f(g(x))) runs:

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

The problem appears when I try to write it like this

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

GHCi says:

"Conflicting definitions for `f'
 Bound at: Lab1.hs:27:9
           Lab1.hs:27:12"

Line 27:9 appear on the first time f and line 27:12 appear f again.

Why doesn't Haskell understand (.) f f = (\x -> f (f x))?


Solution

  • In Haskell, arguments to a function must have unique names. Using the same name for another argument is not allowed. This is because

    foo x y = ...    ===    foo = (\x-> (\y-> ...))
    

    and if y where replaced with x, the second x would just shadow the first inside the ... body: there would be no way to reference the first x from there.

    You can just define twice f x = f (f x):

    Prelude> :t twice
    twice :: (t -> t) -> t -> t
    Prelude> twice (+1) 4
    6


    Alternatively, f (f x) = (.) f f x = join (.) f x:

    Prelude Control.Monad> :t join (.)
    join (.) :: (b -> b) -> b -> b

    join is defined in Control.Monad. For functions, it holds that join g x = g x x. It is also known as W combinator.

    E.g. print $ join (.) (+1) 4 prints 6.