更高级类型的Scala.zip,行为怪异

更高级类型的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

在问答之后,我问了如何创建一个具有更高类参数的方法,以便可以使用任何Seq,现在我在使用.zip方法时遇到了一个奇怪的问题。以下代码未编译,complire报告:

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)
  }

}