[Haskell-cafe] Re: Exercise in point free-style

John Hughes rjmh at cs.chalmers.se
Fri Sep 1 13:11:06 EDT 2006

> From: Julien Oster <haskell at lists.julien-oster.de>
> Subject: [Haskell-cafe] Exercise in point free-style
> I was just doing Exercise 7.1 of Hal Daumé's very good "Yet Another
> Haskell Tutorial". It consists of 5 short functions which are to be
> converted into point-free style (if possible).
> It's insightful and after some thinking I've been able to come up with
> solutions that make me understand things better.
> But I'm having problems with one of the functions:
> func3 f l = l ++ map f l
> Looks pretty clear and simple. However, I can't come up with a solution.
> Is it even possible to remove one of the variables, f or l? If so, how?
> Thanks,
> Julien

Oh, YES!!

Two ways to remove l:

func3a f = uncurry ((.map f).(++)) . pair
func3b f = uncurry (flip (++).map f) . pair

And just to make sure they're right:

propab new f l =
  func3 f l == new f l
  where types = f :: Int->Int

quickCheck (propab func3a)
quickCheck (propab func3b)

If you don't mind swapping the arguments, then

propc f l =
  func3 f l == func3c l f
  where types = f :: Int->Int

func3c l = (l++) . (`map` l)

With the arguments swapped, you can even remove both!

propd f l =
  func3 f l == func3d l f
  where types = f :: Int -> Int

func3d = uncurry ((.(flip map)) . (.) . (++)) . pair

MUCH clearer!

The trick is to observe that l is duplicated, so you need to use a 
combinator that duplicates something. The only one available here is pair, 
which you then have to combine with uncurry.

It would be nicer to have

(f &&& g) x = (f x,g x)

available. (&&& is one of the arrow combinators). Then you could remove l by

func3e f = uncurry (++) . (id &&& map f)

which is sort of readable, and remove both by

func3f = (uncurry (++).) . (id &&&) . map


More information about the Haskell-Cafe mailing list