Frage Verwenden Sie funktionale Kombinatoren auf Scala Tupel?


'map' bewahrt die Anzahl der Elemente, daher erscheint es sinnvoll, sie auf einem Tuple zu verwenden.

Meine bisherigen Versuche:

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)

Es sieht ziemlich schmerzhaft aus ... Und ich habe noch nicht einmal angefangen zu versuchen, es wieder in ein Tupel zu verwandeln.
Mache ich es falsch? Könnte die Bibliothek verbessert werden?


43
2018-02-26 06:27


Ursprung


Antworten:


formlos Unterstützt das Mappen und Falten von Tupeln über einen Vermittler HList Darstellung,

Beispiel einer REPL-Sitzung

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)

Wo die Elemente des Tupels unterschiedliche Typen haben, können Sie mit einer polymorphen Funktion mit typspezifischen Fällen abbilden,

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)

Aktualisieren

Wie von formlos 2.0.0-M1 Das Mapping über Tupel wird direkt unterstützt. Die obigen Beispiele sehen jetzt so aus,

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)

27
2018-05-07 18:56



Im Allgemeinen sind die Elementtypen eines Tupels nicht identisch, so dass die Zuordnung nicht sinnvoll ist. Sie können jedoch eine Funktion definieren, um den Sonderfall zu behandeln:

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)

Sie können das Pimp My Library-Muster verwenden, um dies als zu bezeichnen p.map(_ * 2).

AKTUALISIEREN

Auch wenn die Arten der Elemente nicht gleich sind, Tuple2[A, B] ist ein Bifunktor, die mit dem zugeordnet werden können bimap Betrieb.

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

http://gist.github.com/454818


35
2018-02-26 07:11