How to copy arbitrary traversable ?

61 views
Skip to first unread message

Serge

unread,
May 18, 2015, 12:13:38 PM5/18/15
to scala-user
Hello. I need to write a function to copy (with my algorithm) traversable of arbitrary type. This function should return the same type of traversable that passed to the input. I'm trying to do so:

import scala.language.higherKinds
import scala.collection.generic.CanBuildFrom

trait DeepCopy[A] {
  def deepCopy: A
  def deepCopyAs[B]: B = deepCopy.asInstanceOf[B]
}

object DeepCopy {
  def copyTr[A, T[X] <: Traversable[X]](seq: T[A])(implicit cf: CanBuildFrom[T[A], A, T[A]]): T[A] = seq.map[A, T[A]] {
    case x: DeepCopy[_] => x.deepCopyAs[A]
    case x => x
  }(cf)
}

DeepCopy.copyTr(Vector(1, 2, 3))

 
and I get error:

scala> :pa test.scala
Pasting file test.scala...
<console>:19: error: type mismatch;
 found   : scala.collection.generic.CanBuildFrom[T[A],A,T[A]]
 required: scala.collection.generic.CanBuildFrom[Traversable[A],A,T[A]]
                }(cf)
                  ^

If I change code as follows:

import scala.language.higherKinds
import scala.collection.generic.CanBuildFrom

trait DeepCopy[A] {
  def deepCopy: A
  def deepCopyAs[B]: B = deepCopy.asInstanceOf[B]
}

object DeepCopy {
  def copyTr[A, T[X] <: Traversable[X]](seq: T[A])(implicit cf: CanBuildFrom[Traversable[A], A, T[A]]): T[A] = seq.map[A, T[A]] {
    case x: DeepCopy[_] => x.deepCopyAs[A]
    case x => x
  }(cf)
}

DeepCopy.copyTr(Vector(1, 2, 3))

then I get another error:

scala> :pa test.scala
Pasting file test.scala...
<console>:24: error: Cannot construct a collection of type scala.collection.immutable.Vector[Int] with elements of type Int based on a collection of type Traversable[Int].
              DeepCopy.copyTr(Vector(1, 2, 3))
                             ^

What am i doing wrong?

Sonnenschein

unread,
May 20, 2015, 12:04:22 PM5/20/15
to scala...@googlegroups.com
Serge,
the signatures of your the second trial are fine. The compiler just cannot find any implicit CanBuildFrom for Vector[Int]. So to get it working you need to supply a self-made builder. Here is the proof:

DeepCopy.copyTr(Vector(1, 2, 3))(new CanBuildFrom[Traversable[Int], Int, Vector[Int]] {
override def apply(from: Traversable[Int]): mutable.Builder[Int, Vector[Int]] = ???
override def apply(): mutable.Builder[Int, Vector[Int]] = ???
})

Peter

Serge

unread,
May 20, 2015, 1:24:56 PM5/20/15
to scala...@googlegroups.com
Peter, thanks for reply. The idea was to write a generic function for all traversable subtypes. If I provide a separate implementation of CanBuildFrom for each subtype, such a function loses all meaning.
--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Sonnenschein

unread,
May 21, 2015, 9:04:48 AM5/21/15
to scala...@googlegroups.com
You could also bank on newBuilder like

trait DeepCopy {
def deepCopy[A]: A
}

object DeepCopy {
def copyTr[A, T[X] <: Traversable[X]](traversable: T[A]): T[A] = {
val b = traversable.companion.asInstanceOf[GenericCompanion[T]].newBuilder[A]
traversable foreach {
_ match {
case x: DeepCopy => b += x.deepCopy
case x => b += x
}
}
b.result
}
}

DeepCopy.copyTr(Vector(1, 2, 3))

 

Serge

unread,
May 21, 2015, 4:54:42 PM5/21/15
to scala...@googlegroups.com
It seems to work. Thanks.

Som Snytt

unread,
May 22, 2015, 3:28:32 AM5/22/15
to scala-user
Just to clarify the syntax:

    traversable foreach {

      case x: DeepCopy => b += x.deepCopy
      case x => b += x
    }


I was interested to remove the asInstanceOf by getting a tag of T to check b.result.

It's not obvious to me that the underscores would crash the compiler. It doesn't work anyway; this just trades an abide warning for an erasure warning.

  def copyTr[A, T[_] <: Traversable[_]](traversable: T[A])(implicit tag: ClassTag[T[A]]): T[A] = {
    //val b = traversable.companion.asInstanceOf[GenericCompanion[T]].newBuilder[A]
    val b = traversable.companion.newBuilder[A]
    traversable foreach {

      case x: DeepCopy => b += x.deepCopy
      case x => b += x
    }
    b.result match {
      case res: T[A] => res
      case _ => ???
    }
  }



Reply all
Reply to author
Forward
0 new messages