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