4
votes

I am working my way through the "Functional Programming in Scala" book. Chapter 5.2 starts with the following code:

sealed trait Stream[+A]
case object Empty extends Stream[Nothing]
case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

object Stream {
  def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
    lazy val head = hd
    lazy val tail = tl
    Cons(() => head, () => tail)
  }

  def empty[A]: Stream[A] = Empty

  def apply[A](as: A*): Stream[A] =
    if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))

}

Then the following definition is given:

  def headOption: Option[A] = this match {
      case Empty => None
      case Cons(h, t) => Some(h())
    }

I assume it should be part of the companion object. To not get a compile error immediately I add "headOption[A]". But when I include the result into "object Stream" I am getting the error "pattern type is incompatible with expected type; found : myPackage.Empty.type required: myPackage.Stream.type" with "Empty" underlined.

I am a little lost here. What am I doing wrong?

1

1 Answers

4
votes

It should be part of the trait Stream[+A].

Here this refers to the Stream (trait Stream not companion object). Stream can be Empty or it can be Cons. So pattern matching on this makes sense.

headOption gives first element of the stream if available.

    case object Empty extends Stream[Nothing]

    case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

    sealed trait Stream[+A] {
      def headOption: Option[A] = this match {
        case Empty => None
        case Cons(h, t) => Some(h())
      }
    }



    object Stream {

      def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
        lazy val head = hd
        lazy val tail = tl
        Cons(() => head, () => tail)
      }

      def empty[A]: Stream[A] = Empty

      def apply[A](as: A*): Stream[A] =
        if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))


    }

Scala REPL

scala> :paste
// Entering paste mode (ctrl-D to finish)

case object Empty extends Stream[Nothing]

case class Cons[+A](h: () => A, t: () => Stream[A]) extends Stream[A]

sealed trait Stream[+A] {

  def headOption: Option[A] = this match {
    case Empty => None
    case Cons(h, t) => Some(h())
  }

}

object Stream {

  def cons[A](hd: => A, tl: => Stream[A]): Stream[A] = {
    lazy val head = hd
    lazy val tail = tl
    Cons(() => head, () => tail)
  }

  def empty[A]: Stream[A] = Empty

  def apply[A](as: A*): Stream[A] =
    if (as.isEmpty) empty else cons(as.head, apply(as.tail: _*))

}

// Exiting paste mode, now interpreting.

defined object Empty
defined class Cons
defined trait Stream
defined object Stream

scala> Stream.cons(1, Empty).headOption
res0: Option[Int] = Some(1)