Is it possible to accept arbitrary extractor as method argument

153 views Asked by At

I'd like to reuse existing extractors and compose them. A => Option[B] perfectly matches with B => Option[C].

But I'm confused, how could I express such relation in code.

The obvious way is not available for a good reason:

type Extractor[F,T] = {
  def unapply(from : F) : Option[T]
}

def bind[A,B,C](l : Extractor[A,B], r : Extractor[B,C]) = new {
  def unapply(from : A) : Option[C] = l.unapply(from).flatMap(r.unapply _)
}

scalac reply:

Extractors.scala:7: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
    def unapply(from : A) : Option[C] = l.unapply(from).flatMap(r.unapply _)
                ^
Extractors.scala:3: error: Parameter type in structural refinement may not refer to an abstract type defined outside that refinement
    def unapply(from : F) : Option[T]
                ^
two errors found

Internet says it is expected behaviour due to type erasure.

Is it possible to rephrase the code so it would work properly?

1

There are 1 answers

5
chengpohi On

Parameter type in structural refinement may not refer to an abstract type defined outside that refinement`

As the error call out, for structure type can't refer the generic type that defined in outside.

For your example, you can use trait to do the same thing, like:

trait Extractor[F, T] {
  def unapply(from: F): Option[T]
}

def bind[A, B, C](l: Extractor[A, B], r: Extractor[B, C]) = new Extractor[A, C] {
  override def unapply(from: A): Option[C] = l.unapply(from).flatMap(r.unapply)
}