awllower
awllower

Reputation: 571

How to implement f (g x) (h x) point-freely in Haskell?

From this answer one learns how to implement the function \x y z -> f x (g y z) in a pointless way in Haskell, where f and g are functions. And my question is

How to write the function \x -> f (g x) (h x) in a pointfree manner in Haskell? Here f g h are functions for which f (g x) (h x) is defined.

The idea I currently have in mind is something like the following.

uncurry f (mapTuple ($ x) (g, h))

But several tries shows that this is fallacious; even the part map ($ x) [g, h] is suspicious: what if g and h have different ranges?

In addition, readability is not too much an issue here.

Any help is sincerely appreciated.

Upvotes: 1

Views: 628

Answers (4)

awllower
awllower

Reputation: 571

This only serves to collect and put into order the answers in the comments. According to the abstraction-elimination process in the link in the comment by @ PetrPudlák, we can also write

S (S (K f) (S (K g) I)) (S (K h) I),

or, after eta reduction,

S (S (K f) g) h,

where

S x y z = x z (y z)
K x y = x

Specifically in Haskell, thanks to @melpomene for pointing this out, the role of S is played by ap, and that of K by const. Therefore we can write

ap (ap (const f) g) h

In fact we can further reduce:

ap (const f) g = f . g

So our function can be written as:

ap (f . g) h

If translated to Applicative style, we obtain:

f <$> g <*> h

Then this systematic approach can be applied to all lambda terms, and gives the point-free style. :)

Upvotes: 0

erisco
erisco

Reputation: 14329

Applicative-style

f <$> g <*> h

Control.Compose

join ((g ~> h ~> id) f)

Data.Function.Meld

join (f $* g $$ h *$ id)

Data.Function.Tacit

lurryA @N1 (f <$> (g <$> _1) <*> (h <$> _1))
lurryA @N4 (_1 <*> (_2 <*> _4) <*> (_3 <*> _4)) f g h

Upvotes: 2

leftaroundabout
leftaroundabout

Reputation: 120711

The arrow version would be

uncurry f . (g &&& h)

or

(g &&& h) >>> uncurry f

As a diagram:

        g ────
       ╱          ╲
──── &&&      >>>  uncurry f ───
       ╲          ╱
        h ──── 

Upvotes: 6

zigazou
zigazou

Reputation: 1755

As melpomene suggested, \x -> f (g x) (h x) is equivalent to liftM2 f g h.

When you have question concerning how to convert Haskell code into pointfree Haskell code, you can just try Pointfree.io.

It is a great tool which often can tell you when NOT to use pointfree code because it goes completely unreadable sometimes :-)

enter image description here

Upvotes: 4

Related Questions