user451151
user451151

Reputation: 406

Return child type from base trait with type class pattern

I have the following:

trait Grabber[A, B] {
  def name: String
  def grab(a: A): Option[B]
}

object Grabber {
  implicit def toBooleanGrabber[A](s: String, f: A => Option[Boolean]) =
    new BooleanGrabber[A] {
      override val name: String = s
      override def grab(a: A): Option[Boolean] = f(a)
    }

  implicit def toDoubleGrabber[A](s: String, f: A => Option[Double]) =
    new DoubleGrabber[A] {
      override val name: String = s
      override def grab(a: A): Option[Double] = f(a)
    }

  implicit def toLongGrabber[A](s: String, f: A => Option[Long]) =
    new LongGrabber[A] {
      override val name: String = s
      override def grab(a: A): Option[Long] = f(a)
    }

  def apply[A, B](
    s: String, 
    f: A => Option[B]
  )(implicit ev: (String, A => Option[B]) => Grabber[A, B]): Grabber[A, B] =
    ev(s, f)
}

trait BooleanGrabber[A] extends Grabber[A, Boolean]
trait DoubleGrabber[A] extends Grabber[A, Double]
trait LongGrabber[A] extends Grabber[A, Long]

The apply method works fine, but (per its explicit definition) it returns a Grabber[A, B]. Is there a way to change the apply method's signature (slightly, hopefully) to return the children of Grabber[A, B]? For instance, the invocation that uses toBooleanGrabber would ideally return a BooleanGrabber[T], rather than a Grabber[T, Boolean].

Upvotes: 0

Views: 283

Answers (1)

Jasper-M
Jasper-M

Reputation: 15086

You can add an extra type parameter to your apply method.

def apply[A, B, R](
  s: String, 
  f: A => Option[B]
)(implicit ev: (String, A => Option[B]) => R with Grabber[A, B]): R =
  ev(s, f)

Upvotes: 2

Related Questions