Search code examples
haskellpointfree

Applying multiple functions to the same value point-free style in Haskell


I was bored one day and wanted to exercise my brain, so I decided to do the 99 Haskell Problems but restricted myself to doing them in point-free style. A problem that seems to crop up a lot when I'm doing things in point-free style is this: How do you apply multiple functions to the same value while keeping each result as an independent entity? Using pointed notation:

foobar x = [id x, reverse x]

And what I've come up with so far in point-free notation:

foobar' = `map` [id, reverse] ($ x)

I can't seem to get that x off the end of there.


Solution

  • Others have already posted how you can do this using the Reader monad, but that's not the only way. It turns out that your second function is pretty close. I think you meant to post

    foobar' x = (`map` [id, reverse]) ($ x)
    

    Since the x is already near a rightmost position, you're almost there. First, transform the section ($ x) into a function, because it's a bit easier to work with:

    -- by the definition of a right operator section
    foobar'2 x = (`map` [id, reverse]) (\y -> ($) y x)
    

    Next remove the x from the lambda body by bringing a new variable into scope, and applying the function to x

    -- lambda abstraction I think...
    foobar'2 x = (`map` [id, reverse]) $ (\z y -> ($) y z) x
    

    Rewrite this application as a function composition, and then you can eta reduce:

    -- by definition of '.'
    foobar'3 x = (`map` [id, reverse]) . (\z y -> ($) y z) $ x
    
    -- eta reduction
    foobar'4 = (`map` [id, reverse]) . (\z y -> ($) y z)
    

    Finally, notice that we can replace the lambda with a function

    -- by definition of `flip`
    foobar'5 = (`map` [id,reverse]) . flip ($)
    

    and you have a point-free form.