Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Applying lifted functions to tuples (of arbitrary length) in Haskell

Is there any explanation for why a lifted function, when applied to 2-tuple, only applies to the 2nd entry:

f x = x + 1
f <$> (2,2)
    // -> (2,3)

On the other hand, tuples of any other length than 2 return errors. Also

:t f <$>

returns an error. Is it possible to see the type of f <$> when acting on tuples?

Is there any explanation for that behaviour?

The Data.Tuple documentation is extremely brief and has no mention of how functions are lifted to tuples. Is there any source explaining it?


Update. A part of question about 2-tuples is related to this answer, where, however, the above question about multiple length tuples is not addressed.

like image 599
Dmitri Zaitsev Avatar asked Dec 19 '22 10:12

Dmitri Zaitsev


2 Answers

One could (and arguably, GHC should) define a Functor instance for triples and larger tuples. To wit:

instance Functor ((,,) a b) where
    fmap f (a, b, c) = (a, b, f c)

If this instance truly doesn't exist anywhere in base, I suspect that's mostly oversight, though I don't know the history well enough to say for sure. You can include this in any code where it seems useful, with the caveat that you should then absolutely put a fairly strict upper bound on the version of base in your *.cabal file, as this instance might reasonably be included in future versions of base. The PVP allows only the third component of the version to change in such a case, so include at least that many components in your upper bound!

like image 141
Daniel Wagner Avatar answered Dec 28 '22 13:12

Daniel Wagner


Is there any explanation for why a lifted function, when applied to 2-tuple, only applies to the 2nd entry

Because tuples are heterogeneous which means that, in general, it would not make sense to try to apply a function of type b -> c to each component of a tuple of type (a, b).

If you want pairs of values of the same type, you can declare your own type Pair and then have the functor instance apply the function to each component.

data Pair a = Pair { fst :: a
                   , snd :: a }

instance Functor Pair where
  fmap f (Pair fst snd) = Pair (f fst) (f snd)

Is it possible to see the type of f <$> when acting on tuples?

f <$> is a section (a partially applied infix operator). To get its type, you need to wrap it with parentheses like so:

:t (f <$>)

The Data.Tuple documentation is extremely brief and has no mention of how functions are lifted to tuples. Is there any source explaining it?

The combinator (<$>) (and (<*>)) are more general than just for tuples, you can find them in the Control.Applicative module.

like image 30
gallais Avatar answered Dec 28 '22 14:12

gallais