amalloy
amalloy

Reputation: 91897

Removing duplication (with Applicative ((->) t), perhaps?)

I was playing around with a simple function for someone else's Stack Overflow question, and wrote the expression:

f a x ++ f a y

Obviously this is the best way to write that expression in real life, given I have all those variables in scope anyway, but I saw the duplication of f a, and thought "Hey, maybe you can remove that with the Applicative instance for functions". I wound up with:

liftA2 (++) (flip f x) (flip f y) a

which is just awful. Is there some nicer way to remove this duplication?Obviously I could also remove the duplication by binding f a to something in a where clause, but this was intended as an exercise in using built-in functions.

Upvotes: 15

Views: 598

Answers (4)

frasertweedale
frasertweedale

Reputation: 5644

Since the question hinted at a solution using Applicative (although other answers are more elegant)...

((++) <$> ($ x) <*> ($ y)) (f a)

Upvotes: 3

Daniel Wagner
Daniel Wagner

Reputation: 152737

Bikeshedding is fun! Another option would be to use the Monoid instance for functions:

(($x) <> ($y)) (f a)

Upvotes: 15

jub0bs
jub0bs

Reputation: 66244

[...] maybe you can remove that with the Applicative instance for functions.

Do you have to use the Applicative instance of ((->) t)? If you just want to get rid of the duplicated f a, why not use the list monad, instead?

[x, y] >>= f a

or, equivalently,

f a =<< [x, y]

Example:

λ> let f :: Int -> Int -> [Int]; f a x = [a .. x]

λ> f 1 2 ++ f 1 3
[1,2,1,2,3]

λ> [2, 3] >>= f 1
[1,2,1,2,3]

λ> f 1 =<< [2, 3]
[1,2,1,2,3]

Upvotes: 21

melpomene
melpomene

Reputation: 85767

You could do

((++) `on` f a) x y

That doesn't use Applicative, though (sorry).

Upvotes: 22

Related Questions