2017-01-02 112 views
0
通用Traversable的参数方法的递归调用类型不匹配

我可以做一个(傻)drop包装,它接受一些Traversable类型,并返回相同Traversable类型,使用下面的代码:与斯卡拉

import scala.collection.TraversableLike 

def dropN[E, T <: Traversable[E]] 
(xs: T with TraversableLike[E, T], n: Int): T = 
{ 
    xs.drop(n) 
} 

dropN(0 to 3, 1) // returns: Range 1 to 3 

但是,如果我尽量让类似的功能与递归:

// basically finds the tail 
def dropNR[E, T <: Traversable[E]] 
(xs: T with TraversableLike[E, T]): T = 
{ 
    if (xs.size > 1) dropNR[E,T](xs.drop(1)) else xs 
} 

我得到以下信息:Type mismatch: expected T with TraversableLike[E, T], actual: T

同时纯直通递归方法没有编译错误(但显然会永远递归)

def recurse[E, T <: Traversable[E]] 
(xs: T with TraversableLike[E, T]): T = 
{ 
    recurse[E,T](xs) 
} 

为什么我会得到一个Type mismatch当我使用降?

回答

0

原来我需要使用CanBuildFrom

scala> :pa 
// Entering paste mode (ctrl-D to finish) 
import scala.collection.generic.CanBuildFrom 

def dropR[E, D[E] <: Traversable[E]](xs: D[E]) 
(implicit cbf: CanBuildFrom[D[E], E, D[E]]): D[E] = 
{ 
    if (xs.size > 1) dropR[E,D](xs.drop(1).to[D]) else xs.to[D] 
} 

// Exiting paste mode, now interpreting. 

import scala.collection.generic.CanBuildFrom 
dropR: [E, D[E] <: Traversable[E]](xs: D[E])(implicit cbf: scala.collection.generic.CanBuildFrom[D[E],E,D[E]])D[E] 

scala> val l = List(1,2,3) 
l: List[Int] = List(1, 2, 3) 

scala> dropR(l) 
res0: List[Int] = List(3) 

scala> dropR(l.toSeq) 
res1: scala.collection.immutable.Seq[Int] = List(3) 

scala> dropR(l.toSet) 
res2: scala.collection.immutable.Set[Int] = Set(3) 

scala> dropR(l.toBuffer) 
res3: scala.collection.mutable.Buffer[Int] = ArrayBuffer(3) 
1

因为xs.drop(1)返回T,而不是混合在T with Traversable[E]类型混合到原始xs。在recurse中,您将返回未修改的集合,这就是它工作的原因。

我不知道为什么你需要所有这些额外的类型参数(也许是我想的东西),这应该这样做:

def dropNR[E](xs: Traversable[E]): Traversable[E] = { 
    if (xs.size > 1) dropNR[E](xs.drop(1)) else xs 
} 
+0

这是'Tratrable [E]'的返回类型,有什么办法让返回类型与输入类型相同?所以如果我给它一个'Seq [Int]'我想要一个'Seq [Int]'作为回报。 –

+0

也许^^应该是它自己的问题,但这就是我的目标 –

+0

你可以用'CanBuildFrom'构建器来实现。 –