更高级类型的Scala.zip,行为怪异
在问答之后,我问了如何创建一个具有更高类参数的方法,以便可以使用任何Seq,现在我在使用.zip方法时遇到了一个奇怪的问题。以下代码未编译,complire报告:更高级类型的Scala.zip,行为怪异,scala,collections,higher-kinded-types,Scala,Collections,Higher Kinded Types,在问答之后,我问了如何创建一个具有更高类参数的方法,以便可以使用任何Seq,现在我在使用.zip方法时遇到了一个奇怪的问题。以下代码未编译,complire报告: Error:(18, 28) type mismatch; found : Seq[X] required: S[X] itrA.zip(itrB).map { 我不知道S[X]在哪里被转换成Seq[X]。但是,如果我将代码替换为对.zip的调用,使用一个更简单的代码(注释的代码),它简单地将itrA和itr
Error:(18, 28) type mismatch;
found : Seq[X]
required: S[X]
itrA.zip(itrB).map {
我不知道S[X]在哪里被转换成Seq[X]。但是,如果我将代码替换为对.zip的调用,使用一个更简单的代码(注释的代码),它简单地将itrA和itrB的头相加并返回itrA,则编译是成功的
代码是:
object SeqOps {
def sum[X: Numeric, S[Y] <: Seq[Y]](s: Seq[S[X]])
(implicit cbf: CanBuildFrom[Nothing, X, S[X]]): Seq[X] =
/*
This code compiles
s.reduce{(itrA, itrB) =>
val num = implicitly[Numeric[X]]
val sum = new num.Ops(itrA.head).+(itrB.head)
itrA
*/
s.reduce{(itrA, itrB) =>
itrA.zip(itrB).map { // it seems that itrB loses the type here :/
case (a, b) =>
val num = implicitly[Numeric[X]]
val sum = new num.Ops(a).+(b)
sum
}
}
def main(args: Array[String]): Unit = {
sum(Seq(Vector(1), Vector(1)))
}
}
对象SeqOps{
定义和[X:数字,S[Y]
val num=隐式[数值[X]]
val sum=新的数值运算(itrA.head)。+(itrB.head)
伊特拉
*/
s、 减少{(itrA,itrB)=>
itrA.zip(itrB.map{//itrB似乎在这里丢失了类型:/
案例(a,b)=>
val num=隐式[数值[X]]
val sum=新的数值运算(a)。+(b)
总和
}
}
def main(参数:数组[字符串]):单位={
求和(序列(向量(1),向量(1)))
}
}
问题是:为什么会发生这种情况?我如何解决它?它不知道,如果你
zip
两个S[X]
它可以以某种方式构建一个S[(X,X)]
出来。要想让它起作用,你需要一个CBF
知道如何构建S[(X,X)]
不幸的是,似乎没有任何隐含信息能够从泛型的Seq[\ux]构建例如Vector[Int]
,因此您需要更多关于您正在构建的集合类型的信息。想法是,具有类似于-Like
名称的特征可以提供此信息。在这种情况下,SeqLike[X,Repr]
携带Repr
-type
如果您现在长时间盯着屏幕看:
然后你会看到你可以给它一个CBF
,它在第一个组件中有Repr
。所以你可以尝试这样的东西(注意和SeqLike
,两个CBF
s-一个用于zip
,另一个用于map
):
导入scala.collection.generic.CanBuildFrom
导入scala.language.higherKinds
导入scala.collection.SeqLike
对象SeqOps{
定义和[X:数字,S[Y]a+b})
}
def main(参数:数组[字符串]):单位={
println(sum(Seq(向量(1),向量(1)))//向量(2)
println(sum(Seq)(列表(2,3),列表(4,5))//列表(6,8)
}
}
另一句话:在某些情况下,更容易将Nothing
视为Unobtanium
。如果您的CBF
需要Unobtanium
来构建S[X]
,它可能对任何东西都没有好处,因为您想从哪里获得Unobtanium
def zip
[A1 >: A, B, That]
(that: GenIterable[B])
(implicit bf: CanBuildFrom[Repr, (A1, B), That])
: That
import scala.collection.generic.CanBuildFrom
import scala.language.higherKinds
import scala.collection.SeqLike
object SeqOps {
def sum[X: Numeric, S[Y] <: Seq[Y] with SeqLike[Y, S[Y]]]
(s: Seq[S[X]])
(implicit
cbf1: CanBuildFrom[S[_], X, S[X]],
cbf2: CanBuildFrom[S[_], (X, X), S[(X, X)]]
)
: Seq[X] = {
val num = implicitly[Numeric[X]]
import num._
s.reduce(_.zip(_)(cbf2).map{ case (a, b) => a + b })
}
def main(args: Array[String]): Unit = {
println(sum(Seq(Vector(1), Vector(1)))) // Vector(2)
println(sum(Seq(List(2, 3), List(4, 5)))) // List(6, 8)
}
}