通用‘地图’ Scala 元组的函数?

发布于 2024-09-29 06:25:17 字数 1492 浏览 0 评论 0原文

我想使用返回类型 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

错々过的事 2024-10-06 06:25:18

这可以使用 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)

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:

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)

(I had to add a val in front of i in the definition of Super, this way: class Super(val i: Int), so that it can be accessed outside)

花辞树 2024-10-06 06:25:18

这里更深层次的问题是“为什么要使用元组来实现这个目的?”

元组在设计上是异构的,并且可以包含各种非常不同的类型。如果您想要相关事物的集合,那么您应该使用...鼓声...集合!

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

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 or Sequence 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.

花想c 2024-10-06 06:25:18

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

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

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

For the case when the two functions to be applied are not the same

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

The main reason I have supplied this answer is it works for lists of tuples (just change Some to List and remove the get).

寂寞美少年 2024-10-06 06:25:17

我认为这就是您正在寻找的:

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)

I think this is what you're looking for:

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)

A more "functional" way to do this would be with 2 separate functions:

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)
金兰素衣 2024-10-06 06:25:17

我不是 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)) }

I’m not a scala type genius but maybe this works:

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)) }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文