I am trying concatenate a series of Traversable
views in Scala using a foldLeft
operator and am hitting type variance errors that I don't understand.
I can use reduce
to concatenate a list of Traversable
views like so.
val xs = List(1,2,3,4).map(Traversable(_).view).reduce((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b) // TraversableView[Int,Traversable[_]]
// xs.force returns Traversable[Int] = List(1, 2, 3, 4)
(Note that I have to write the type annotation on the reduce
arguments: reduce(_ ++ _)
does not compile. I don't understand why and would be grateful for an explanation of this too.)
I can also break the list up into a head and a tail and concatenate them.
import collection.TraversableView
val ns = List(1,2,3,4)
val h = Traversable(ns.head).view
val t = ns.tail.map(Traversable(_).view).reduce((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
val xs = h ++ t // TraversableView[Int,Traversable[_]]
// xs.force returns Traversable[Int] = List(1, 2, 3, 4)
But if I try to do the same thing with a foldLeft
I get type variance errors.
import collection.TraversableView
val ns = List(1,2,3,4)
val h = Traversable(ns.head).view
val t = ns.tail.map(Traversable(_).view)
val xs = (h /: t)((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
<console>:14: error: type mismatch;
found : scala.collection.TraversableView[Int,Traversable[_]]
required: java.lang.Object with scala.collection.TraversableView[Int,Traversable[Int]]
(h /: t)((a: TraversableView[Int, Traversable[_]], b: TraversableView[Int, Traversable[_]]) => a ++ b)
I suspect the issue has to do with the existential type in Traversable[_]
, but I can't figure out what exactly I'm doing wrong. I've tried various type signatures in the above expression to no avail. Judging from other questions on Stackoverflow, there is something tricky about the typing of foldLeft
, but I couldn't find one that addresses this issue.
For comparison, the same algorithm with Stream
works without a hitch.
val xs = (1 #:: Stream.empty /: List(2,3,4).map(_ #:: Stream.empty))(_ ++ _)
// xs.force returns Stream[Int] = Stream(1, 2, 3, 4)
The above is what I want to do, except I want to use a view instead of Stream
because I don't need to memoize all my results.
This might seem like an odd request. The reason I want to do things this way is because performing foldLeft
over Traversable
views provides an efficient way to implement a lazy depth first search.