通用‘地图’ Scala 元组的函数?
我想使用返回类型 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 不支持多种类型的类型边界吗?如果是,为什么不呢?
I would like to map the elements of a Scala tuple (or triple, ...) using a single function returning type R. The result should be a tuple (or triple, ...) with elements of type R.
OK, if the elements of the tuple are from the same type, the mapping is not a problem:
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)
But is it also possible to make this solution generic, i.e. to map tuples that contain elements of different types in the same manner?
Example:
class Super(i: Int)
object Sub1 extends Super(1)
object Sub2 extends Super(2)
(Sub1, Sub2) map (_.i)
should return
(1,2): (Int, Int)
But I could not find a solution so that the mapping function determines the super type of Sub1 and Sub2. I tried to use type boundaries, but my idea failed:
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)) }
Here X >: B
seems to override X >: A
. Does Scala not support type boundaries regarding multiple types? If yes, why not?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
这可以使用 shapeless 轻松实现,尽管在进行映射之前您必须先定义映射函数:(
在
Super
的定义中,我必须在i
前面添加一个val
,这样:class Super(val i :int)
,这样就可以外部访问了)This can easily be achieved using shapeless, although you'll have to define the mapping function first before doing the map:
(I had to add a
val
in front ofi
in the definition ofSuper
, this way:class Super(val i: Int)
, so that it can be accessed outside)这里更深层次的问题是“为什么要使用元组来实现这个目的?”
元组在设计上是异构的,并且可以包含各种非常不同的类型。如果您想要相关事物的集合,那么您应该使用...鼓声...集合!
Set
或Sequence
对性能没有影响,并且更适合此类工作。毕竟,这就是它们的设计目的。The deeper question here is "why are you using a Tuple for this?"
Tuples are hetrogenous by design, and can contain an assortment of very different types. If you want a collection of related things, then you should be using ...drum roll... a collection!
A
Set
orSequence
will have no impact on performance, and would be a much better fit for this kind of work. After all, that's what they're designed for.对于要应用的两个函数不相同的情况
我提供这个答案的主要原因是它适用于元组列表(只需将 Some 更改为 List 并删除 get )。
For the case when the two functions to be applied are not the same
The main reason I have supplied this answer is it works for lists of tuples (just change Some to List and remove the get).
我认为这就是您正在寻找的:
一种更“实用”的方法是使用两个独立的函数:
I think this is what you're looking for:
A more "functional" way to do this would be with 2 separate functions:
我不是 scala 类型的天才,但也许这有效:
I’m not a scala type genius but maybe this works: