Use functional combinators on Scala Tuples?

前端 未结 3 1257
滥情空心
滥情空心 2020-11-30 05:51

\'map\' preserves the number of elements, so using it on a Tuple seems sensible.

My attempts so far:

scala> (3,4).map(_*2)    
error: value map is         


        
相关标签:
3条回答
  • 2020-11-30 05:55

    shapeless Supports mapping and folding over tuples via an intermediary HList representation,

    Sample REPL session,

    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)
    

    Where the elements of the tuple are of different types you can map with a polymorphic function with type-specific cases,

    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)
    

    Update

    As of shapeless 2.0.0-M1 mapping over tuples is supported directly. The above examples now look like this,

    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)
    
    0 讨论(0)
  • 2020-11-30 06:00

    In general, the element types of a tuple aren't the same, so map doesn't make sense. You can define a function to handle the special case, though:

    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)
    

    You could use the Pimp My Library pattern to call this as p.map(_ * 2).

    UPDATE

    Even when the types of the elements are not the same, Tuple2[A, B] is a Bifunctor, which can be mapped with the bimap operation.

    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

    0 讨论(0)
  • 2020-11-30 06:07

    map function gets an A => B and returns F[B].

    def map[A, B](f: A => B) : F[B]
    

    As retronym wrote Tuple2[A, B] is a Bifunctor, so you can look for the bimap function in scalaz or cats.
    bimap is a function that maps both sides of the tuple:

    def bimap[A, B, C, D](fa: A => C, fb: B => D): Tuple2[C, D]
    

    Because Tuple[A, B] holds 2 values and only one value can be mapped (by convention the right value), you can just return the same value for the left side and use the right function to map over the right value of the tuple.

    (3, 4).bimap(identity, _ * 2)
    
    0 讨论(0)
提交回复
热议问题