Reputation: 8412
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
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
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