5.4
Implement forAll, which checks that all elements in the Stream match a given predicate. Your implementation should terminate the traversal as soon as it encounters a nonmatching value.
def forAll(p: A => Boolean): Boolean
Solution
object Solution extends App {
val streamMultiple10: Stream[Int] = Stream(10,20,30,40)
val streamMultiple10Error: Stream[Int] = Stream(10,20,3,4)
println("streamMultiple10:" + streamMultiple10.toList)
val streamAllWell: Boolean = streamMultiple10.forAll(_%10 == 0)
println("streamMultiple10 forAll? " + streamAllWell)
println("streamMultiple10Error:" + streamMultiple10Error.toList)
val streamNotWell: Boolean = streamMultiple10Error.forAll(_%10 == 0)
println("streamMultiple10Error forAll? " + streamNotWell)
}
import scala.annotation
trait Stream[+A] {
import Stream._
def forAll(p: A => Boolean): Boolean = this match {
case Cons(h, t) if p(h()) => t().forAll(p)
case Cons(h, t) if !p(h()) => false
case empty => true
}
def toList: List[A] = {
@annotation.tailrec
def go(l: List[A], s: Stream[A]): List[A] = s match {
case Empty => l.reverse
case Cons(h,t) => go(h()::l, t())
}
go(List(), this)
}
}
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]
object Stream {
def empty[A]: Stream[A] = Empty
def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
lazy val head = hd
lazy val tail = tl
Cons(() => head, () => tail)
}
def apply[A](as: A*): Stream[A] =
if(as.isEmpty) empty else cons(as.head, apply(as.tail: _*))
}
Output
streamMultiple10:List(10, 20, 30, 40)
streamMultiple10 forAll? true
streamMultiple10Error:List(10, 20, 3, 4)
streamMultiple10Error forAll? false