在 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
Use functional combinators on Scala Tuples?
提问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
回答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)

