Он не знает, что если вы zip
два S[X]
, то он может каким-то образом построить из него S[(X, X)]
.Чтобы это работало, вам нужен CBF
, который знает, как построить S[(X, X)]
.
К сожалению, не существует каких-либо последствий, которые могли бы построить, например, Vector[Int]
изуниверсальный Seq[_]
, поэтому вам нужно больше информации о типе коллекции, из которой вы строите.Идея состоит в том, что черты с именем -Like
могут предоставить эту информацию.В этом случае SeqLike[X, Repr]
содержит тип Repr
.
Если вы теперь достаточно долго смотрите на подпись zip
в SeqLike
:
def zip
[A1 >: A, B, That]
(that: GenIterable[B])
(implicit bf: CanBuildFrom[Repr, (A1, B), That])
: That
, то вы увидите, что можете дать емуCBF
с Repr
в первом компоненте.Так что вы можете попробовать что-то вроде этого (примечание with SeqLike
и два CBF
с - один для zip
, другой для map
):
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)
}
}
Еще одно замечание: в некоторых случаях этопроще думать о Nothing
как о Unobtanium
.Если вашему CBF
требуется Unobtanium
для построения S[X]
, это, вероятно, ни к чему не годится, потому что, где вы хотите получить Unobtanium
?