Reputation: 87
I have a function of the following form:
def tTest[T](it1 : TraversableOnce[T], it2 : Option[TraversableOnce[T]] = None)
(implicit frac: Fractional[T]) = {
...
}
My intent is to call it like so:
tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )
and also sometimes like:
tTest( Array(1.0,2,3,4) )
The second one works fine, but when I try to call the first, I get the following:
scala:14: type mismatch;
found : Option[Array[Double]]
required: Option[TraversableOnce[?]]
[EDIT] this code works fine:
tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7).toTraversable) )
My question is this: What is the relationship between Array and TraversableOnce in Scala? Intuitively, I would think the above should work, since an array is in fact traversable at least once.
On a practical note, what is the simplest way to get this to work for Arrays, Sets, Streams, and any other data structure that is traversable once?
Upvotes: 2
Views: 1790
Reputation: 18869
Here is another solution:
scala> def tTest[T, C[_]](it1: C[T], it2: Option[C[T]] = None)
| (implicit frac: math.Fractional[T], ev: C[T] => TraversableOnce[T]): TraversableOnce[T] = ev(it1)
tTest: [T, C[_]](it1: C[T], it2: Option[C[T]])(implicit frac: scala.math.Fractional[T], implicit ev: C[T] => scala.collection.TraversableOnce[T])scala.collection.TraversableOnce[T]
scala> tTest( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )
res0: scala.collection.TraversableOnce[Double] = [D(1.0, 2.0, 3.0, 4.0)
scala> tTest( Array(1.0,2,3,4) )
res1: scala.collection.TraversableOnce[Double] = [D(1.0, 2.0, 3.0, 4.0)
EDIT The above solution doesn't work for following case:
scala> tTest(Array(1.2), Option(List(2.0)))
<console>:9: error: inferred kinds of the type arguments (Double,Object) do not conform to the expected kinds of the type parameters (type T,type C).
Object's type parameters do not match type C's expected parameters:
class Object has no type parameters, but type C has one
tTest(Array(1.2), Option(List(2.0)))
^
<console>:9: error: type mismatch;
found : Array[Double]
required: C[T]
tTest(Array(1.2), Option(List(2.0)))
So, here is a more complex and flexible one:
scala> import math.Fractional
import math.Fractional
scala> import collection.{TraversableOnce => TO}
import collection.{TraversableOnce=>TO}
scala> def tTest2[T, C1[_], C2[_]](i1: C1[T], i2: Option[C2[T]])
| (implicit fc: Fractional[T],
| e1: C1[T] => TO[T],
| e2: C2[T] => TO[T]): TO[T] = e1(i1)
scala> tTest2(Array(1.2, 2.3), Option(List(2.3)))
res5: scala.collection.TraversableOnce[Double] = [D(1.2, 2.3)
scala> tTest2(Array(1.2, 2.3), Option(Array(2.3)))
res6: scala.collection.TraversableOnce[Double] = [D(1.2, 2.3)
Upvotes: 1
Reputation: 3294
Firstly, your code doesn't work because type inference is confused. Specify type perameter explicitly:
tTest[Double]( Array(1.0,2,3,4), Option(Array(1.0,8,7)) )
Array[T] is Scala's representation for Java's T[]. Array is not a Scala Collection/Traversable. It is implicitly converted to one but it is not an instance of a Traversable.
To see a nice overview of Scala collections and their relatioship, check this: http://docs.scala-lang.org/overviews/collections/overview.html
You can also use implicit conversion:
import scala.language.implicitConversions
implicit def conv[T](a: Option[Array[T]]): Option[Traversable[T]] = a.map(_.toTraversable)
Personaly I usually use Iterable[T] if the only thing I need to do is to simply run through all elements, but it's not optimal in general. Here is some reasoning about it: Scala: What is the difference between Traversable and Iterable traits in Scala collections?
Upvotes: 3