2015-04-26 28 views
1

我难以使flatUnzip的隐式需求正常工作。目前看起来第一个要求ATuple2[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) 
    } 
    } 

EDIT

我发现了以下工作,但只有当=:=在方向上施加如图所示:

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[Tuple2[CC1[T1], CC2[T2]]] =:= Seq[A]Tuple2[CC1[T1], CC2[T2]] =:= A与替换Seq[A] =:= Seq[Tuple2[CC1[T1], CC2[T2]]]A =:= Tuple2[CC1[T1], CC2[T2]]会导致问题。有人可以解释为什么这里的订单很重要,为什么需要这些A =:= B关系中的每一个来完成这项工作?

+0

nitpick:这里不需要'return' –

+0

nitpick#2:'[T1,T2,CC1 [T1],CC2 [T2]]'并不意味着你的想法。你可以只写'[T1,T2,CC1 [_],CC2 [_]]'。 –

回答

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

UPDATE:

,正如你在编辑的问题指出,这些修正都不足以使代码工作。你找到了自己需要的附加修复程序,但它们为什么要工作?

这是因为=:=提供的证据不仅仅是一个被忽略的虚拟值。 =:=延伸Function1,它的功能呢?它从左侧的类型转换为右侧的类型。在运行时,它什么都不做(它是一个身份函数);但在编译时,可能需要应用该函数才能将左侧的类型转换为右侧的类型。

在您的修订代码中,ev2用于输入,将_seq转换为正确的类型。如果使用-Xprint:typer编译代码,您将看到明确的呼叫ev2,ev3ev4

哦,恩,那么ev1呢?我不确定。这不会在编译的代码中显示出来。我现在没有看到为什么需要它。编译器似乎需要它作为垫脚石才能派生出ev2

更新#2:

啊哈!对于ev2,请使用<:<,而不是=:=。那么你不需要ev1了。

+0

这似乎仍然会导致问题。当我运行它'新的MySeq(列表( (列表(1,2,3),列表(11,12,13)), (列表(4,5,6),列表(14,15,16 )), (List(7,8,9),List(17,18,19)) ))。flatUnzip'它说'不能证明Seq [(List [Int],List [Int])] = := Seq [(CC1 [T1],CC2 [T2])]' – Kvass

+0

为什么'ev1'需要在输出端使用?输出的类型是'(CC1 [T1],CC2 [T2])',它没有被定义为w.r.t. 'A' – Kvass

+0

嗯,你是对的。我不知道为什么需要'ev1'。 '-Xprint:typer'不会提供任何线索。我已经适当地编辑了我的答案。 –