代码之家  ›  专栏  ›  技术社区  ›  Stefan Endrullis

Scala元组的通用“map”函数?

  •  9
  • Stefan Endrullis  · 技术社区  · 15 年前

    我想用一个返回R类型的函数映射Scala元组(或triple,…)的元素。结果应该是一个包含R类型元素的元组(或triple,…)。

    scala> implicit def t2mapper[A](t: (A,A)) = new { def map[R](f: A => R) = (f(t._1),f(t._2)) }
    t2mapper: [A](t: (A, A))java.lang.Object{def map[R](f: (A) => R): (R, R)}
    
    scala> (1,2) map (_ + 1)
    res0: (Int, Int) = (2,3)
    

    但是,是否也可以使此解决方案通用,即以相同方式映射包含不同类型元素的元组?

    例子:

    class Super(i: Int)
    object Sub1 extends Super(1)
    object Sub2 extends Super(2)
    
    (Sub1, Sub2) map (_.i)
    

    应该回来

    (1,2): (Int, Int)
    

    但我找不到解决方案,所以映射函数决定了Sub1和Sub2的超类型。我试图使用类型界限,但我的想法失败了:

    scala> implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
    <console>:8: error: X is already defined as type X
           implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
                                                                        ^
    <console>:8: error: type mismatch;
     found   : A
     required: X
     Note: implicit method t2mapper is not applicable here because it comes after the application point and it lacks an explicit result type
           implicit def t2mapper[A,B](t: (A,B)) = new { def map[X >: A, X >: B, R](f: X => R) = (f(t._1),f(t._2)) }
    

    X >: B 似乎凌驾于 X >: A . Scala不支持关于多个类型的类型边界吗?如果是,为什么不呢?

    5 回复  |  直到 15 年前
        1
  •  11
  •   Tom Crockett    15 年前

    我想这就是你要找的:

    implicit def t2mapper[X, A <: X, B <: X](t: (A,B)) = new {
      def map[R](f: X => R) = (f(t._1), f(t._2))
    }
    
    scala> (Sub1, Sub2) map (_.i)                             
    res6: (Int, Int) = (1,2)
    

    更“实用”的方法是使用两个独立的功能:

    implicit def t2mapper[A, B](t: (A, B)) = new { 
      def map[R](f: A => R, g: B => R) = (f(t._1), g(t._2)) 
    }       
    
    scala> (1, "hello") map (_ + 1, _.length)                                         
    res1: (Int, Int) = (2,5)
    
        2
  •  4
  •   Debilski    15 年前

    我不是斯卡拉式的天才,但也许这行得通:

    implicit def t2mapper[X, A<:X, B<:X](t: (A,B)) = new { def map[A, B, R](f: X => R) = (f(t._1),f(t._2)) }
    
        3
  •  0
  •   Kevin Wright    15 年前

    更深层的问题是“为什么要使用元组?”

    元组在设计上是不同的,可以包含非常不同类型的分类。如果你想收集相关的东西,那么你应该使用 …鼓卷。。。 收藏!

    一个 Set Sequence

        4
  •  0
  •   samthebest Ende Neu    12 年前

    当要应用的两个函数不相同时

    scala> Some((1, "hello")).map((((_: Int) + 1 -> (_: String).length)).tupled).get
    res112: (Int, Int) = (2,5)
    

        5
  •  0
  •   Alex Archambault    12 年前

    这可以通过使用 shapeless ,尽管在执行映射之前必须先定义映射函数:

    object fun extends Poly1 {
      implicit def value[S <: Super] = at[S](_.i) 
    }
    
    (Sub1, Sub2) map fun // typed as (Int, Int), and indeed equal to (1, 2)
    

    (我不得不加上一个 val i 在定义中 Super ,这边: class Super(val i: Int)

    推荐文章