Ali Afshar
Ali Afshar

Reputation: 41643

Is there a nicer way to apply a function to both elements of a pair in a list than a list comprehension?

I use this a fair bit:

a' = [ (f x, f y) | (x, y) <- a ]

Is there a better way to do that?

Upvotes: 11

Views: 983

Answers (3)

Landei
Landei

Reputation: 54584

Alternative solution:

import Data.Bifunctor

bimap f f pair

Bifunctor.bimap is basically the same as Arrow.(***), but works for other bifunctors (like Either a b), too.

Digression:

The reason why there is nothing predefined for your case is that you can't write instances of Functor, Applicative etc for (,) having the same element type twice. With an own "vector-like" type you wouldn't have this problem:

data Pair a = Pair a a deriving Show

instance Functor Pair where
  fmap f (Pair x y) = Pair (f x) (f y)

Now you can write things like map (fmap (+1)) [Pair 12 14, Pair 17 18]. Or if you want to use different operations on your Pair, you can go one step further:

instance Applicative Pair where 
  pure x = Pair x x
  (Pair f g) <*> (Pair x y) = Pair (f x) (g y)

If you work a lot with same-element-type pairs, it could be useful to switch from (,) to such a type.

Upvotes: 11

shachaf
shachaf

Reputation: 8930

If you use lens, you can use over both f, or both %~ f. This has the advantage of being more composable -- for example, if you have a pair of lists, you can use something like both.mapped +~ toUpper (:: ([Char],[Char]) -> ([Char],[Char])).

Upvotes: 5

hammar
hammar

Reputation: 139850

You can use the (***) operator from Control.Arrow

> map (f *** f) a

or define your own helper function

> let both f (x, y) = (f x, f y)
> map (both f) a

Upvotes: 15

Related Questions