David House dmhouse at gmail.com
Thu Jan 11 11:34:14 EST 2007

```On 11/01/07, Marco Túlio Gontijo e Silva <malebria at riseup.net> wrote:
> is there a way to defined something as a map to use in tuples? I tried
> this:
>
> mapTuple f (a, b) = (f a, f b)
>
> But the type inferred to it is not as generic as I wanted:
>
> mapTuple :: (t -> t1) -> (t, t) -> (t1, t1)

Let's think about what type we might want to give this. Here's a first attempt:

mapTuple :: (a -> c) -> (a, b) -> (c, d)
mapTuple f (x, y) = (f x, f y)

But this won't typecheck, because we can only apply the function to
the first element in the tuple from the type that we have. In other
words, we don't know that we can pass values of type b into f. We
could say:

mapTuple :: (a -> c) -> (a, a) -> (c, c)

But this isn't as polymorphic as you'd like. An alternative is sum types:

mapTuple :: (Either a b -> c) -> (a, b) -> (c, c)
mapTuple f (x, y) = (f \$ Left x, f \$ Right y)

Note that we can't do:

mapTuple :: (Either a b -> Either c d) -> (a, b) -> (c, d)

Because we don't know that feeding a value of type c into f will yield
a value of type d; f (Left x) might return a Right-tagged value. We
could perhaps do this:

mapTuple :: (Either a b -> (c, d)) -> (a, b) -> (c, d)
mapTuple f (x, y) = (fst \$ f \$ Left x, snd \$ f \$ Right y)

And a function would then return both a value of type c and d
(possibly one of them being undefined). However, it doesn't really
seem satisfactory to impose this constraint on our arguments. Instead,
it seems we want to supply two functions:

mapTuple :: (a -> b) -> (c - >d) -> (a, b) -> (c, d)

And this appears now as a the classic f × g operation over pairs,
implemented as (***) in Control.Arrow:

(***) :: (a -> b) -> (c -> d) -> (a, b) -> (c, d)
(f *** g) (x, y) = (f x, g y)

(Actually the original is a little lazier, using irrefutable patterns
on the pair.) Then you can do:

(show *** show) ("string", True)

And I suspect that's the best you'll get. There may be a wild solution
involving typeclasses and existentials, but this doesn't seem