Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Any built-in fmap-of-sorts on all values of a tuple?

Tags:

haskell

For now I have this little helper:

both f (one,two) = (f one , f two)

Then I was idly wondering whether fmap "iterates" a tuple so I asked GHCi:

fmap reverse ("aA","bB")

Result being:

("aA","Bb")

Odd! So the semantics of fmap over a tuple seems to be "to apply func to the snd", if you will.

Anything in base or Prelude I should use instead of my own both? Hoogle gave no promising results or I parsed them wrongly.

like image 232
metaleap Avatar asked Nov 28 '22 22:11

metaleap


2 Answers

In terms of "mapping" over both elements of a tuple, the best you have is bimap :: Bifunctor p => (a -> b) -> (c -> d) -> p a c -> p b d defined in Data.Bifunctor (now in base!). With that, you can write

ghci> bimap reverse reverse ("aA","bB")
("Aa","Bb")

Alternately, you can use (***) :: Arrow a => a b c -> a b' c' -> a (b, b') (c, c') defined in Control.Arrow (in particular using the Arrow (->) instance). With that, you can write

ghci> (reverse *** reverse) ("aA","bB")
("Aa","Bb")

However, if you are trying to map over both elements of a tuple at the same time, perhaps you are looking for an abstraction that groups together two values of type a. If this is the case, I would recommend you use a newtype around (a,a). Then, you can turn on the -XDeriveFunctor extension as get the following

ghci> :set -XDeriveFunctor
ghci> newtype Pair a = Pair (a,a) deriving (Show,Functor)
ghci> fmap reverse (Pair ("aA","bB"))
Pair ("Aa","Bb")
like image 191
Alec Avatar answered Dec 05 '22 02:12

Alec


You need to consider the full type. In the type (a,b), which is the same a s (,) a b, the functor is (,) a. Hence we get

fmap :: (b -> c) -> (,) a b -> (,) a c

This makes it clear that the first component is unaffected by fmap.

> fmap reverse (True,"bB")
(True,"Bb")

You are probably thinking of another functor

-- user-defined
data Pair a = Pair a a deriving Functor

Here we do have

fmap :: (b -> c) -> Pair b -> Pair c

affecting both components, but this type is not the regular tuple type.

Bonus puzzle: for the same reason

> length (1,2)
1
like image 22
chi Avatar answered Dec 05 '22 04:12

chi