'map' préserve le nombre d'éléments, son utilisation sur un tuple semble donc judicieuse.
Mes tentatives jusqu'ici:
scala> (3,4).map(_*2)
error: value map is not a member of (Int, Int)
(3,4).map(_*2)
^
scala> (3,4).productIterator.map(_*2)
error: value * is not a member of Any
(3,4).productIterator.map(_*2)
^
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2)
res4: Iterator[Int] = non-empty iterator
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2).toList
res5: List[Int] = List(6, 8)
Cela semble assez douloureux ... Et je n'ai même pas commencé à essayer de le reconvertir en Tuple.
Est-ce que je me trompe? La bibliothèque pourrait-elle être améliorée?
informe supporte le mapping et le repliement des n-uplets via une représentation intermédiaire HList
,
Exemple de session REPL,
scala> import shapeless._ ; import Tuples._
import shapeless._
import Tuples._
scala> object double extends (Int -> Int) (_*2)
defined module double
scala> (3, 4).hlisted.map(double).tupled
res0: (Int, Int) = (6,8)
Lorsque les éléments du tuple sont de types différents, vous pouvez mapper avec une fonction polymorphe avec des cas spécifiques au type,
scala> object frob extends Poly1 {
| implicit def caseInt = at[Int](_*2)
| implicit def caseString = at[String]("!"+_+"!")
| implicit def caseBoolean = at[Boolean](!_)
| }
defined module frob
scala> (23, "foo", false, "bar", 13).hlisted.map(frob).tupled
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)
Mise à jour
À partir de sans forme 2.0.0-M1 , le mappage sur des nuplets est directement pris en charge. Les exemples ci-dessus ressemblent maintenant à ceci,
scala> import shapeless._, poly._, syntax.std.Tuple._
import shapeless._
import poly._
import syntax.std.Tuple._
scala> object double extends (Int -> Int) (_*2)
defined module double
scala> (3, 4) map double
res0: (Int, Int) = (6,8)
scala> object frob extends Poly1 {
| implicit def caseInt = at[Int](_*2)
| implicit def caseString = at[String]("!"+_+"!")
| implicit def caseBoolean = at[Boolean](!_)
| }
defined module frob
scala> (23, "foo", false, "bar", 13) map frob
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)
En général, les types d'éléments d'un tuple ne sont pas identiques, ainsi la carte n'a pas de sens. Vous pouvez définir une fonction pour gérer le cas particulier, cependant:
scala> def map[A, B](as: (A, A))(f: A => B) =
as match { case (a1, a2) => (f(a1), f(a2)) }
map: [A,B](as: (A, A))(f: (A) => B)(B, B)
scala> val p = (1, 2)
p: (Int, Int) = (1,2)
scala> map(p){ _ * 2 }
res1: (Int, Int) = (2,4)
Vous pouvez utiliser le modèle Pimp My Library pour appeler ceci sous la forme p.map(_ * 2)
.
UPDATE
Même lorsque les types des éléments ne sont pas identiques, Tuple2[A, B]
est un Bifunctor , qui peut être mappé avec l'opération bimap
.
scala> import scalaz._
import scalaz._
scala> import Scalaz._
import Scalaz._
scala> val f = (_: Int) * 2
f: (Int) => Int = <function1>
scala> val g = (_: String) * 2
g: (String) => String = <function1>
scala> f <-: (1, "1") :-> g
res12: (Int, String) = (2,11)
UPDATE 2
la fonction map obtient une A
et retourne F[B]
.
def map[A, B](f: A => F[B]) : F[B]
Comme l'a écrit retronym, Tuple2 [A, B] est un bifunctor, vous pouvez donc rechercher la fonction bimap dans scalaz ou chez les chats.
bimap est une fonction qui mappe les deux côtés du tuple:
def bimap[A, B, C, D](fa: A => C, fb: B => D): Tuple2[C, D]
Étant donné que Tuple [A, B] contient 2 valeurs et qu’une seule valeur peut être mappée (par convention, la valeur correcte), vous pouvez simplement renvoyer la même valeur pour le côté gauche et utiliser la fonction droite Pour mapper sur la bonne valeur du tuple.
(3, 4).bimap(identity, _ * 2)