在 Scala 元组上使用函数组合器?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/2339863/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-22 01:58:39  来源:igfitidea点击:

Use functional combinators on Scala Tuples?

scaladictionarytuplesshapeless

提问by Eldritch Conundrum

'map' preserves the number of elements, so using it on a Tuple seems sensible.

'map' 保留元素的数量,因此在元组上使用它似乎是明智的。

My attempts so far:

我到目前为止的尝试:

scala> (3,4).map(_*2)    
error: value map is not a member of (Int, Int)
       (3,4).map(_*2)
             ^
scala> (3,4).productIterator.map(_*2)
error: value * is not a member of Any
       (3,4).productIterator.map(_*2)
                                  ^
scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2)
res4: Iterator[Int] = non-empty iterator

scala> (3,4).productIterator.map(_.asInstanceOf[Int]*2).toList
res5: List[Int] = List(6, 8)

It looks quite painful... And I haven't even begun to try to convert it back to a tuple.
Am I doing it wrong? Could the library be improved?

它看起来很痛苦......我什至还没有开始尝试将它转换回元组。
我做错了吗?图书馆可以改进吗?

采纳答案by Miles Sabin

shapelessSupports mapping and folding over tuples via an intermediary HListrepresentation,

shapeless支持通过中间HList表示映射和折叠元组,

Sample REPL session,

示例 REPL 会话,

scala> import shapeless._ ; import Tuples._
import shapeless._
import Tuples._

scala> object double extends (Int -> Int) (_*2)
defined module double

scala> (3, 4).hlisted.map(double).tupled
res0: (Int, Int) = (6,8)

Where the elements of the tuple are of different types you can map with a polymorphic function with type-specific cases,

如果元组的元素属于不同类型,您可以使用具有特定类型情况的多态函数进行映射,

scala> object frob extends Poly1 {
     |   implicit def caseInt     = at[Int](_*2)
     |   implicit def caseString  = at[String]("!"+_+"!")
     |   implicit def caseBoolean = at[Boolean](!_)
     | }
defined module frob

scala> (23, "foo", false, "bar", 13).hlisted.map(frob).tupled
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)

Update

更新

As of shapeless 2.0.0-M1mapping over tuples is supported directly. The above examples now look like this,

从 shapeless 2.0.0-M1 开始,直接支持元组上的映射。上面的例子现在看起来像这样,

scala> import shapeless._, poly._, syntax.std.tuple._
import shapeless._
import poly._
import syntax.std.tuple._

scala> object double extends (Int -> Int) (_*2)
defined module double

scala> (3, 4) map double
res0: (Int, Int) = (6,8)

scala> object frob extends Poly1 {
     |   implicit def caseInt     = at[Int](_*2)
     |   implicit def caseString  = at[String]("!"+_+"!")
     |   implicit def caseBoolean = at[Boolean](!_)
     | }
defined module frob

scala> (23, "foo", false, "bar", 13) map frob
res1: (Int, String, Boolean, String, Int) = (46,!foo!,true,!bar!,26)

回答by retronym

In general, the element types of a tuple aren't the same, so map doesn't make sense. You can define a function to handle the special case, though:

一般来说,元组的元素类型是不一样的,所以 map 没有意义。不过,您可以定义一个函数来处理特殊情况:

scala> def map[A, B](as: (A, A))(f: A => B) = 
     as match { case (a1, a2) => (f(a1), f(a2)) } 
map: [A,B](as: (A, A))(f: (A) => B)(B, B)

scala> val p = (1, 2)    
p: (Int, Int) = (1,2)

scala> map(p){ _ * 2 }
res1: (Int, Int) = (2,4)

You could use the Pimp My Library pattern to call this as p.map(_ * 2).

您可以使用 Pimp My Library 模式将其称为p.map(_ * 2).

UPDATE

更新

Even when the types of the elements are not the same, Tuple2[A, B]is a Bifunctor, which can be mapped with the bimapoperation.

即使元素的类型不同,Tuple2[A, B]也是一个Bifunctor,它可以与bimap操作映射。

scala> import scalaz._
import scalaz._

scala> import Scalaz._
import Scalaz._

scala> val f = (_: Int) * 2
f: (Int) => Int = <function1>

scala> val g = (_: String) * 2
g: (String) => String = <function1>

scala> f <-: (1, "1") :-> g
res12: (Int, String) = (2,11)

UPDATE 2

更新 2

http://gist.github.com/454818

http://gist.github.com/454818

回答by Sagi

map function gets an A => Band returns F[B].

map 函数获取A => B并返回F[B]

def map[A, B](f: A => B) : F[B]

As retronym wrote Tuple2[A, B] is a Bifunctor, so you can look for the bimap function in scalaz or cats.
bimap is a function that maps both sides of the tuple:

正如retronym 所写,Tuple2[A, B] 是一个Bifunctor,所以你可以在scalaz 或cats 中寻找bimap 函数。
bimap 是一个映射元组两侧的函数:

def bimap[A, B, C, D](fa: A => C, fb: B => D): Tuple2[C, D]

Because Tuple[A, B] holds 2 values and only one value can be mapped (by convention the right value), you can just return the same value for the left side and use the right function to map over the right value of the tuple.

因为 Tuple[A, B] 包含 2 个值并且只能映射一个值(按照约定是正确的值),您可以只为左侧返回相同的值并使用正确的函数来映射元组的正确值.

(3, 4).bimap(identity, _ * 2)