Implicit parameters won't work on unapply. How to hide ubiquitous parameters from extractors?

此生再无相见时 提交于 2019-12-05 16:15:28

In what sense does your first line of code not work? There's certainly no arbitrary prohibition on implicit parameter lists for extractor methods.

Consider the following setup (I'm using plain old classes instead of case classes to show that there's no extra magic happening here):

class A(val i: Int)
class C(val x: String)
class B(pre: String) { def getC(a: A) = new C(pre + a.i.toString) }

Now we define an implicit B value and create an extractor object with your unapply method:

implicit val b = new B("prefix: ")

object D {
  def unapply(a: A)(implicit b: B): Option[C] = Option(b getC a)
}

Which we can use like this:

scala> val D(c) = new A(42)
c: C = C@52394fb3

scala> c.x
res0: String = prefix: 42

Exactly as we'd expect. I don't see why you need a workaround here.

The problem you have is that implicit parameters are compile time (static) constraints, whereas pattern matching is a runtime (dynamic) approach.

trait A; trait C; trait B { def getC(a: A): C }

object Extractor {
  def unapply(a: A)(implicit b: B): Option[C] = Some(b.getC(a))
}

// compiles (implicit is statically provided)
def withImplicit(a: A)(implicit b: B) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}

// does not compile
def withoutImplicit(a: A) : Option[C] = a match { 
  case Extractor(c) => Some(c)
  case _            => None
}

So this is a conceptual problem, and the solution depends on what you actually want to achieve. If you want something along the lines of an optional implicit, you might use the following:

sealed trait FallbackNone {
  implicit object None extends Optional[Nothing] {
    def toOption = scala.None
  }
}
object Optional extends FallbackNone {
  implicit def some[A](implicit a: A) = Some(a)
  final case class Some[A](a: A) extends Optional[A] { 
    def toOption = scala.Some(a)
  }
}
sealed trait Optional[+A] { def toOption: Option[A]}

Then where you had implicit b: B you will have implicit b: Optional[B]:

object Extractor {
   def unapply(a:A)(implicit b: Optional[B]):Option[C] = 
      b.toOption.map(_.getC(a))
}

def test(a: A)(implicit b: Optional[B]) : Option[C] = a match { 
   case Extractor(c) => Some(c)
   case _            => None
}

And the following both compile:

test(new A {}) // None

{
  implicit object BImpl extends B { def getC(a: A) = new C {} }
  test(new A {}) // Some(...)
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!