Haskell: how to map a tuple?

2019-01-30 17:55发布

In Haskell, I can easily map a list:

map (\x -> 2*x) [1,2]

gives me [2,4]. Is there any "mapTuple" function which would work like that?

mapTuple (\x -> 2*x) (1,2)

with the result being (2,4).

13条回答
做个烂人
2楼-- · 2019-01-30 18:00

You can also use lens to map tuples:

import Control.Lens
mapPair = over both

Or you can map over tuples with upto 10 elements:

mapNtuple f = traverseOf each (return . f)
查看更多
We Are One
3楼-- · 2019-01-30 18:00

To add another solution to this colourful set... You can also map over arbitrary n-tuples using Scrap-Your-Boilerplate generic programming. For example:

import Data.Data
import Data.Generics.Aliases

double :: Int -> Int
double = (*2)

tuple :: (Int, Int, Int, Int)
tuple = gmapT (mkT double) (1,2,3,4)

Note that the explicit type annotations are important, as SYB selects the fields by type. If one makes one tuple element type Float, for example, it wouldn't be doubled anymore.

查看更多
叼着烟拽天下
4楼-- · 2019-01-30 18:03

Here's a rather short point-free solution:

import Control.Monad (join)
import Control.Arrow ((***))

mapTuple = join (***)
查看更多
Viruses.
5楼-- · 2019-01-30 18:03

The extra package provides the both function in the Data.Tuple.Extra module. From the docs:

Apply a single function to both components of a pair.

> both succ (1,2) == (2,3)

both :: (a -> b) -> (a, a) -> (b, b)
查看更多
啃猪蹄的小仙女
6楼-- · 2019-01-30 18:05

You can use arrows from module Control.Arrow to compose functions that work on tuples.

Prelude Control.Arrow> let f = (*2) *** (*2)
Prelude Control.Arrow> f (1,2)
(2,4)
Prelude Control.Arrow> let f' = (*2) *** (*3)
Prelude Control.Arrow> f (2,2)
(4,4)
Prelude Control.Arrow> f' (2,2)
(4,6)

Your mapTuple then becomes

mapTuple f = f *** f

If with your question you asked for a function that maps over tuples of arbitrary arity, then I'm afraid you can't because they would have different types (e.g. the tuple types (a,b) and (a,b,c) are totally different and unrelated).

查看更多
姐就是有狂的资本
7楼-- · 2019-01-30 18:09

Yes, you would do:

map (\x -> (fst x *2, snd x *2)) [(1,2)]

fst grabs the first data entry in a tuple, and snd grabs the second; so, the line of code says "take a tuple, and return another tuple with the first and second items double the previous."

查看更多
登录 后发表回答