fabian789
fabian789

Reputation: 8412

Short way to write (\(x, y) -> (f x, g y))

For functions f :: a → b, g :: c → d, how do I write the lambda

\(x, y) → (f x, g y) :: (a, b) → (c, d)

more concisely? I tried (f, g) but – as was to be expected I guess – without success.

Upvotes: 7

Views: 257

Answers (3)

chepner
chepner

Reputation: 531165

The Bifunctor instance of (,) is what you are looking for:

instance Bifunctor (,) where
  bimap f g (a, b) = (f a, g b)

bimap applies two functions to a tuple, one to each element.

> import Data.Bifunctor
> bimap (+1) (*5) (1,1)
(2, 5)

You might be wondering what the difference between bimap and (***) is.

> :t bimap
bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d
> :t (***)
(***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c')

With bimap, you can restrict the type to tuples rather than an arbitrary bifunctor p, so that with p ~ (,), the type of bimap becomes

 (a -> b) -> (c -> d) -> (a, c) -> (b, d).

With (***), you can restrict the type to functions rather than an arbitrary arrow a, so that with a ~ (->), the type of (***) becomes

 (b -> c) -> (b' -> c') -> (b, b') -> (c, c')

A close look reveals the two restricted types are equivalent.

Upvotes: 16

Steven Shaw
Steven Shaw

Reputation: 6249

Try

import Control.Arrow

answer = f *** g $ (a, c)

e.g.

import Control.Arrow

f :: Int -> Int
f = (+1)

g :: Double -> String
g = show

answer = f *** g $ (10, 3.5)

Upvotes: 7

Lee
Lee

Reputation: 144136

You can use (***) from Control.Arrow i.e.

f *** g

Upvotes: 9

Related Questions