概述';地图';Scala元组的函数?

概述';地图';Scala元组的函数?,scala,tuples,contravariance,superclass,Scala,Tuples,Contravariance,Superclass,我想使用返回类型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的单个函数映射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)) }
scala>隐式def t2mapper[A,B](t:(A,B))=新的{def-map[X>:A,X>:B,R](f:X=>R)=(f(t.)1,f(t.)2))]
:8:错误:X已定义为类型X
隐式def t2mapper[A,B](t:(A,B))=新的{def映射[X>:A,X>:B,R](f:X=>R)=(f(t.1),f(t.2))}
^
:8:错误:类型不匹配;
发现:A
必填项:X
注意:隐式方法t2mapper在这里不适用,因为它位于应用程序点之后,并且缺少显式结果类型
隐式def t2mapper[A,B](t:(A,B))=新的{def映射[X>:A,X>:B,R](f:X=>R)=(f(t.1),f(t.2))}

这里
X>:B
似乎覆盖了
X>:A
。Scala不支持关于多个类型的类型边界吗?如果是,为什么不呢?

我想这就是你想要的:

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)

我不是一个scala类型的天才,但也许这是可行的:

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)) }

implicit def t2mapper[X,A这里更深层次的问题是“为什么要使用元组?”

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


集合
序列
对性能没有影响,更适合此类工作。毕竟,这就是它们的设计目的。

适用于两个应用函数不相同的情况

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

我提供这个答案的主要原因是它适用于元组列表(只需将一些更改为List并删除get即可)。

这可以通过使用轻松实现,尽管在进行映射之前必须先定义映射函数:

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)
对象1{

隐式def value集合对于我来说太灵活了,因为它们的元素数量可变。这段代码是用Scala编写的内部DSL的一部分,我希望在编译时确保用户指定的函数正好处理2个参数(元组)。此外,如果我在闭包定义中使用集合而不是元组,它们会变得更详细,因为我不能再使用模式匹配(“案例(a,b)”)。关于模式匹配:您可以在集合上进行匹配:列表(1,2,3)匹配{案例列表(a,b,c)=>…}.@mkneissl:True,但是您会丢失类型安全wrt元素数:
List(1,2,3,4)match{case List(a,b,c)=>…}
在运行时失败。这看起来像是HLists的情况。请参阅示例
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)