Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

like image 593
Dwilson Avatar asked Jul 29 '12 12:07

Dwilson


3 Answers

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.

like image 192
John L Avatar answered Nov 05 '22 13:11

John L


You will be interested in the Applicative instance of the reader monad:

instance Applicative (e ->)

Using it you can easily distribute an argument:

liftA2 (+) sin cos 3

Here sin and cos are functions, which both receive the value 3. The individual results are then combined using (+). You can further combine this with the Category instance of (->), but of cource specialized versions of (.) and id are already defined in the Prelude.

Background: The Applicative instance for (e ->) really represents the SKI calculus, where (<*>) is the S combinator and pure is the K combinator. S is precisely used to distribute an argument to two functions:

S f g x = f x (g x)

It takes a function application (f g) and makes both dependent on the value x ((f x) (g x)).

like image 16
ertes Avatar answered Nov 05 '22 14:11

ertes


Use sequence:

> let foobar' = sequence [id, reverse]
> foobar' "abcde"
["abcde","edcba"]
like image 15
Matvey Aksenov Avatar answered Nov 05 '22 14:11

Matvey Aksenov