Search code examples
haskellpointfree

Write f in pointfree-style?


Say I have functions

g :: a -> b, h :: a -> c 

and

f :: b -> c -> d. 

Is it possible to write the function

 f' :: a -> a -> d 

given by

f' x y = f (g x) (h y) 

in point free style?.

One can write the function

f' a -> d, f' x = f (g x) (h x) 

in point free style by setting

f' = (f <$> g) <*> h  

but I couldn't figure out how to do the more general case.


Solution

  • We have:

    k x y = (f (g x)) (h y)
    

    and we wish to write k in point-free style.

    The first argument passed to k is x. What do we need to do with x? Well, first we need to call g on it, and then f, and then do something fancy to apply this to (h y).

    k = fancy . f . g
    

    What is this fancy? Well:

    k x y = (fancy . f . g) x y
          = fancy (f (g x)) y
          = f (g x) (h y)
    

    So we desire fancy z y = z (h y). Eta-reducing, we get fancy z = z . h, or fancy = (. h).

    k = (. h) . f . g
    

    A more natural way to think about it might be

                                 ┌───┐           ┌───┐
                            x ───│ g │─── g x ───│   │
                          /      └───┘           │   │
                   (x, y)                        │ f │─── f (g x) (h y)
                          \      ┌───┐           │   │
                            y ───│ h │─── h y ───│   │
                                 └───┘           └───┘
    
                          └──────────────────────────────┘
                                          k
    

    Enter Control.Arrow:

    k = curry ((g *** h) >>> uncurry f)