1

why is this code working fine for Lists and Vectors but fails for a WrappedString?

implicit class TraversableExt[A, CC[A] <: TraversableLike[A, CC[A]]](lst: CC[A]) {
  def filterPairs(f: (A, A) => Boolean)(implicit bf: CanBuildFrom[CC[A], A, CC[A]]): CC[A] = {
    def filterPairs(lst: TraversableLike[A, CC[A]], result: Builder[A, CC[A]]): CC[A] = {
      if(lst.isEmpty) result.result
      else if(lst.tail.isEmpty) (result += lst.head).result
      else if(!f(lst.head, lst.tail.head)) filterPairs(lst.tail, result)
      else filterPairs(lst.tail, result += lst.head)
    }
    filterPairs(lst, bf())
  }
}
println(List(1,2,2,3).filterPairs(_ != _))

If I call the method explicitly

println(TraversableExt(new WrappedString("hi thhere")).filterPairs(_ != _))

I get this error

error: inferred type arguments [Char,scala.collection.AbstractSeq] do not conform to method TraversableExt's type parameter bounds [A,CC[A] <: scala.collection.TraversableLike[A,CC[A]]]
println(TraversableExt(new WrappedString("hi thhere")).filterPairs(_ != _))
Tesseract
  • 8,049
  • 2
  • 20
  • 37

1 Answers1

3

[A, CC[A] <: TraversableLike[A, CC[A]]](lst: CC[A])

WrappedString is TraversableLike[Char, WrappedString]. WrappedString takes no type parameter, so it can't be CC[A].

You could use IsTraversableOnce:

import collection.generic.{IsTraversableOnce, CanBuildFrom}
import collection.GenTraversableOnce

class TraversableExt[A, Repr](val lst: GenTraversableOnce[A]) {
  def filterPairs[That](f: (A, A) => Boolean)(implicit cbf: CanBuildFrom[Repr, A, That]): That = {
    val b = cbf()
    var prev: Option[A] = None
    for ( e <- lst ) {
      for {
        pr <- prev
        if f(pr, e)
      } b += pr
      prev = Some(e)
    }
    b ++= prev
    b.result
  }
}
implicit def toTraversableExt[Repr](coll: Repr)(implicit tr: IsTraversableOnce[Repr]) =
  new TraversableExt[tr.A, Repr](tr.conversion(coll))

scala> List(1,2,2,3).filterPairs(_ != _)
res0: List[Int] = List(1, 2, 3)

scala> "abbcccddddeaa".filterPairs(_ != _)
res1: String = abcdea
senia
  • 37,745
  • 4
  • 88
  • 129
  • Tnank you, but how do I fix this? Simply replacing CC[A] with CC doesn't work. – Tesseract May 16 '13 at 14:55
  • @SpiderPig Use [`IsTraversableLike`](http://www.scala-lang.org/api/current/index.html#scala.collection.generic.IsTraversableLike). – Daniel C. Sobral May 16 '13 at 14:57
  • @SpiderPig I've added an implementation with `IsTraversableOnce`. – senia May 16 '13 at 15:41
  • Thanks a lot. This works perfectly. I didn't know about IsTraversableOnce. Do you know where the type "That" comes from? I mean how is the compiler even able to infer the type of "That"? It also works if you replace That with Repr. – Tesseract May 16 '13 at 20:07
  • @SpiderPig: about `That`: see [the best answer on the topic scala collections ever](http://stackoverflow.com/a/1716558/406435) by Daniel C. Sobral. And [here](http://www.devoxx.com/display/FR13/Martin+Odersky) (starting from 42:40) Martin Odersky himself explains where the type `That` comes from. – senia May 16 '13 at 20:24