Search code examples
haskelltuplescurryingarrowspointfree

How to implement uncurry point-free in Haskell without app?


I have been wondering how different standard Haskell functions could be implemented point-free. Currently, I am interested in uncurry and I feel this one is quite non-trivial.

The main problem is that we are unable (or as it seems to me) to group the arguments. If we had uncurry (in fact, uncurry ($) would suffice) in use, the solution would have been quite simple:

  1. Make a tuple (f, (x, y)).
  2. Apply assoc1 :: (a, (b, c)) -> ((a, b), c) to the tuple and get ((f, x), y).
  3. Apply the uncurried ($) to the first element of the pair and get (f x, y).
  4. Apply the uncurried ($) to the pair itself and get f x y.

Without the uncurried ($) we would have to extract both elements of the pair separately. E.g.:

uncurry f pair = f (fst pair) (snd pair)

I do not reckon this to be a smooth way to implement something point-free.

In fact, we have got this uncurried ($) at our behest: Control.Arrow.apply (other useful for the solution combinators could also be imported from Control.Arrow). Therefore:

import Control.Arrow ((>>>), (&&&), first, app)

myUncurry = let myAssoc1 = (fst &&& (fst . snd)) &&& (snd . snd)
            in (,) >>> (>>> myAssoc1 >>> first app >>> app) 

Yet, this feels a small bit like cheating.

Are there any other approaches towards this problem which do not require anything like app?


Solution

  • join on functions gives you (a -> a -> b) -> a -> b, so:

    myUncurry f = join (\x y -> f (fst x) (snd y))
    myUncurry f = join (\x -> f (fst x) . snd)
    myUncurry f = join ((.snd) . f . fst)
    myUncurry f = join ((.fst) ((.snd) . f))
    myUncurry f = join ((.fst) ((.) (.snd) f))
    myUncurry = join . (.fst) . \f -> (.) (.snd) f
    myUncurry = join . (.fst) . ((.snd).)
    

    join . (.fst) . ((.snd).) is very readable indeed