Filter function for streaming processor with contravariant input parameter compile error

Viewed 51

I am trying to implement the Stream transducer described in Functional Programming in Scala in chapter 15. The authors do not use variance for the process type parameters Process[I, O]. However on the pursuit of really understanding variance, I added variance to the type parameters as such: Process[-I, +O]. All was well until I tried implementing the filter function and got the following compile error:

contravariant type I occurs in covariant position in type I => Boolean of value p

This is the setup code that I have been working with:

 sealed trait Process[-I, +O] { self =>
    import Process._

    def apply(s: Stream[I]): Stream[O] = this match {
      case Halt => Stream()
      case Await(recv) =>
        s match {
          case h #:: t => recv(Some(h))(t)
          case xs      => recv(None)(xs)
        }
      case Emit(h, t) => h #:: t(s)
    }

    def filter(p: I => Boolean): Process[I, O] = self match {
      case Halt => Halt
      case Await(recv) =>
        Await {
          case Some(i) if (p(i)) => recv(Some(i))
          case _                 => recv(None)
        }
      case Emit(head, tail) => Emit(head, tail.filter(p))
    }
  }

  object Process {

    case class Emit[I, O](
        head: O,
        tail: Process[I, O] = Halt
    ) extends Process[I, O]

    case class Await[I, O](
        recv: Option[I] => Process[I, O]
    ) extends Process[I, O]

    case object Halt extends Process[Any, Nothing]
  }

I have already tried modifying filter signature to this: def filter[II >: I](p: I => Boolean): Process[II, O]

Also tried changing Await to have the following type params:

case class Await[I, O, II >: I](
        recv: Option[I] => Process[II, O]
    ) extends Process[I, O]

But still did not manage to compile this code.

Any ideas?

1 Answers

Try

def filter[II <: I](p: II => Boolean): Process[II, O] = ...

with the original Await.

Related