The Bifunctor (,) instance is what you are looking for:
instance Bifunctor (,) where bimap fg (a, b) = (fa, gb)
bimap applies two functions to a tuple, one for each element.
> import Data.Bifunctor > bimap (+1) (*5) (1,1) (2, 5)
You might be wondering what the difference is between bimap and (***) .
> :t bimap bimap :: Bifunctor p => (a -> b) -> (c -> d) -> pac -> pbd > :t (***) (***) :: Arrow a => abc -> ab' c' -> a (b, b') (c, c')
With bimap you can restrict the type to tuples, rather than an arbitrary p bifunter, so if p ~ (,) the bimap type becomes
(a -> b) -> (c -> d) -> (a, c) -> (b, d).
With (***) you can restrict the type to functions, rather than the arbitrary arrow a , so that with a ~ (->) type (***) becomes
(b -> c) -> (b' -> c') -> (b, b') -> (c, c')
A close look reveals that two limited types are equivalent.
chepner
source share