10

我想使用返回类型 R 的单个函数映射 Scala 元组(或三元组,...)的元素。结果应该是一个具有 R 类型元素的元组(或三元组,...)。

OK,如果元组的元素来自相同的类型,映射不是问题:

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 不支持关于多种类型的类型边界吗?如果是,为什么不呢?

4

5 回答 5

12

我想这就是你要找的:

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)
于 2010-10-26T09:51:23.880 回答
4

我不是 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)) }
于 2010-10-26T09:55:00.390 回答
0

这里更深层次的问题是“你为什么要为此使用元组?”

元组在设计上是异质的,并且可以包含各种非常不同的类型。如果你想要一个相关的东西的集合,那么你应该使用...drum roll...一个集合!

A SetorSequence对性能没有影响,并且更适合这种工作。毕竟,这就是他们的设计目的。

于 2010-10-26T10:15:55.123 回答
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前面加了一个,这样:,这样就可以在外面访问了)iSuperclass Super(val i: Int)

于 2014-07-20T16:54:59.560 回答
0

对于要应用的两个功能不相同的情况

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

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

于 2013-11-30T13:17:44.383 回答