我很难使flatUnzip
的隐含要求正常工作。目前看来A
是Tuple2[CC1[T1], CC2[T2]]
的第一个要求被忽略(因此完整性检查无法编译)。这里有什么建议?在回答时,请解释我目前的尝试有什么问题。
class MySeq[A](val _seq: Seq[A]) extends AnyVal {
def flatUnzip[T1, T2, CC1[T1], CC2[T2]](
implicit ev1: A =:= Tuple2[CC1[T1], CC2[T2]],
ev2: CC1[T1] <:< TraversableOnce[T1],
ev3: CC2[T2] <:< TraversableOnce[T2],
cbf1: CanBuildFrom[CC1[T1], T1, CC1[T1]],
cbf2: CanBuildFrom[CC2[T2], T2, CC2[T2]]
): (CC1[T1], CC2[T2]) = {
val foo: Seq[Tuple2[CC1[T1], CC2[T2]]] = _seq // sanity check fails
val list1 = cbf1()
val list2 = cbf2()
for ((xs, ys) <- _seq) {
list1 ++= xs
list2 ++= ys
}
return (list1.result, list2.result)
}
}
修改
我发现以下情况有效,但仅当=:=
按照所示方向应用时才会有效:
class MySeq[A](val _seq: Seq[A]) extends AnyVal {
def mapBy[B](func: A => B): Map[B, A] = _seq.map(x => (func(x), x)).toMap
def flatUnzip[T1, T2, CC1[T1], CC2[T2]](
implicit
ev1: Tuple2[CC1[T1], CC2[T2]] =:= A,
ev2: Seq[A] =:= Seq[Tuple2[CC1[T1], CC2[T2]]],
ev3: CC1[T1] <:< TraversableOnce[T1],
ev4: CC2[T2] <:< TraversableOnce[T2],
cbf1: CanBuildFrom[CC1[T1], T1, CC1[T1]],
cbf2: CanBuildFrom[CC2[T2], T2, CC2[T2]]
): (CC1[T1], CC2[T2]) = {
val list1 = cbf1()
val list2 = cbf2()
for ((xs, ys) <- _seq: Seq[Tuple2[CC1[T1], CC2[T2]]]) {
list1 ++= xs
list2 ++= ys
}
return (list1.result, list2.result)
}
}
但是,将Seq[A] =:= Seq[Tuple2[CC1[T1], CC2[T2]]]
替换为Seq[Tuple2[CC1[T1], CC2[T2]]] =:= Seq[A]
或Tuple2[CC1[T1], CC2[T2]] =:= A
替换为A =:= Tuple2[CC1[T1], CC2[T2]]
会导致问题。有人可以解释为什么这里的订单很重要,以及为什么需要这些A =:= B
关系中的每一个才能使这项工作成功?
答案 0 :(得分:1)
您可以通过将ev1
更改为:
implicit ev1: Seq[A] =:= Seq[Tuple2[CC1[T1], CC2[T2]]],
仅仅因为您有A
=:=
某种类型的证据,并不意味着证据也适用于Seq[A]
。因此,请直接询问您实际需要的证据。
您还需要将for
理解更改为:
for ((xs, ys) <- _seq: Seq[Tuple2[CC1[T1], CC2[T2]]]) {
如果没有用于触发搜索的类型转换,编译器就不会去寻找ev1
。
<强>更新强>
正如您在编辑过的问题中指出的那样,这些修补程序不足以使代码正常工作。您自己找到了所需的其他修补程序,但为什么它们有效?
这是因为=:=
提供的证据不仅仅是一个被忽略的虚拟值。 =:=
扩展Function1
,它的功能是什么?它从左侧的类型转换为右侧的类型。在运行时,它什么都不做(它是一个身份函数);但是在编译时,可能需要应用该函数才能将左侧的类型转换为右侧的类型。
在修改后的代码中,输入使用ev2
,将_seq
转换为正确的类型。如果您使用-Xprint:typer
编译代码,则会看到对ev2
,ev3
和ev4
的显式调用。
哦,呃,ev1
怎么样?我不确定。这并没有出现在已编译的代码中。我现在没有看到它为什么需要它。编译器似乎需要它作为跳板才能派生ev2
。
更新#2:
啊哈!对于ev2
,请使用<:<
,而不是=:=
。那你就不再需要ev1
了。