I am following the book Functional programming in Scala and in particular the section where you implement a simple Stream trait and companion object. For reference, here is what we have so far in the companion obejct
object Stream {
def empty[A]: Stream[A] =
new Stream[A] {
def uncons = None
}
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] =
new Stream[A] {
lazy val uncons = Some((hd, tl))
}
def apply[A](as: A*): Stream[A] =
if (as.isEmpty)
empty
else
cons(as.head, apply(as.tail: _*))
}
and the trait so far:
trait Stream[A] {
import Stream._
def uncons: Option[(A, Stream[A])]
def toList: List[A] = uncons match {
case None => Nil: List[A]
case Some((a, as)) => a :: as.toList
}
def #::(a: => A) = cons(a, this)
def take(n: Int): Stream[A] =
if (n <= 0)
empty
else (
uncons
map { case (a, as) => a #:: (as take (n - 1)) }
getOrElse empty
)
}
The next exercise requires me to write an implementation for takeWhile and I thought the following would do
def takeWhile(f: A => Boolean): Stream[A] = (
uncons
map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty }
getOrElse empty
)
Unfortunately, is seems that I get a variance error that I am not able to track down:
error: type mismatch; found : Stream[_2] where type _2 <: A
required: Stream[A]
Note: _2 <: A, but trait Stream is invariant in type A.
You may wish to define A as +A instead. (SLS 4.5)
getOrElse empty
^
I could add a variance annotation, but before doing that I would like to understand what is going wrong here. Any suggestions?
this seems to be an issue with type inference, because it works if you explicitly specify the type of the subexpression
uncons map { case (a, as) => if (f(a)) (a #:: (as takeWhile f)) else empty }.