我想使用返回类型R的单个函数映射Scala元组(或三元组......)的元素。结果应该是元组类型为R的元组(或三元组...)。
好的,如果元组的元素来自同一类型,则映射不是问题:
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不支持多种类型的类型边界吗?如果是,为什么不呢?
答案 0 :(得分:11)
我认为这就是你要找的东西:
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)
更“实用”的方法是使用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)
答案 1 :(得分:4)
我不是斯卡拉类型的天才,但也许这有效:
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)) }
答案 2 :(得分:0)
这里更深层次的问题是“你为什么要使用元组?”
元组在设计上属于hetrogenous,可以包含各种不同类型的元素。如果你想要一组相关的东西,那么你应该使用 ... drum roll ... 一个集合!
Set
或Sequence
对性能没有任何影响,并且更适合此类工作。毕竟,这就是他们的目标。
答案 3 :(得分:0)
对于要应用的两个函数不相同的情况
scala> Some((1, "hello")).map((((_: Int) + 1 -> (_: String).length)).tupled).get
res112: (Int, Int) = (2,5)
我提供这个答案的主要原因是它适用于元组列表(只需将Some更改为List并删除get)。
答案 4 :(得分:0)
使用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
的{{1}}定义前面添加i
,这样:Super
,以便可以在外面访问< / p>