Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

enrich PartialFunction with unapply functionality

PartialFunction is a natural extractor, its lift method provides exact extractor functionality. So it would be very convenient to use partial functions as extractors. That would allow to combine pattern matching expressions in more complicated way than plain orElse that is available for PartialFunction

So I tried to use pimp my library approach and had failed


Here goes update: As @Archeg shown, there is another approach to conversion that works. So I'm including it to the provided code.

I'm tried also some more complex solutions and they failed


object Test {
  class UnapplyPartial[-R, +T](val fun : PartialFunction[R,T]) {
    def unapply(source : R) : Option[T] = fun.lift(source)
  }
  implicit def toUnapply[R,T](fun : PartialFunction[R,T]) : UnapplyPartial[R,T] = new UnapplyPartial(fun)

  class PartialFunOps[-R, +T](val fun : PartialFunction[R,T]) {
    def u : UnapplyPartial[R, T] = new UnapplyPartial(fun)
  }
  implicit def toPartFunOps[R,T](fun : PartialFunction[R,T]) : PartialFunOps[R,T] = new PartialFunOps(fun)


  val f : PartialFunction[String, Int] = {
    case "bingo" => 0
  }
  val u = toUnapply(f)

  def g(compare : String) : PartialFunction[String, Int] = {
    case `compare` => 0
  }

   // error while trying to use implicit conversion
  def testF(x : String) : Unit = x match {
    case f(i) => println(i)
    case _ => println("nothing")
  }

  // external explicit conversion is Ok
  def testU(x : String) : Unit = x match {
    case u(i) => println(i)
    case _ => println("nothing")
  }

 // embedded explicit conversion fails
  def testA(x : String) : Unit = x match {
    case toUnapply(f)(i) => println(i)
    case _ => println("nothing")
  }

  // implicit explicit conversion is Ok
  def testI(x : String) : Unit = x match {
    case f.u(i) => println(i)
    case _ => println("nothing")
  }

  // nested case sentences fails
  def testInplace(x : String) : Unit = x match {
    case { case "bingo" => 0 }.u(i) => println(i)
    case _ => println("nothing")
  }

  // build on the fly fails
  def testGen(x : String) : Unit = x match {
    case g("bingo").u(i) => println(i)
    case _ => println("nothing")
  }

  // implicit conversion without case is also Ok
  def testFA(x : String) : Option[Int] =
    f.unapply(x)
}

I got the following error messages:

UnapplyImplicitly.scala:16: error: value f is not a case class, nor does it have an unapply/unapplySeq member case f(i) => println(i)

UnapplyImplicitly.scala:28: error: '=>' expected but '(' found. case toUnapply(f)(i) => println(i)

This errors may be avoided with supposed form as TestI shown. But I'm curious if it is possible to avoid testInplace error:

UnapplyImplicitly.scala:46: error: illegal start of simple pattern case { case "bingo" => 0 }.u(i) => println(i) ^

UnapplyImplicitly.scala:47: error: '=>' expected but ';' found. case _ => println("nothing")

UnapplyImplicitly.scala:56: error: '=>' expected but '.' found. case g("bingo").u(i) => println(i) ^

like image 878
ayvango Avatar asked Dec 07 '25 22:12

ayvango


1 Answers

I'm not sure what you are trying to achieve in the end, but as far as I understand extractors should always be objects, there is no way you can get it with a class. It is actually called Extractor Object in the documentation. Consider this:

class Wrapper[R, T](fun: PartialFunction[R, T]) {
  object PartialExtractor {
    def unapply(p: R): Option[T] = fun.lift(p)
  }
}

implicit def toWrapper[R,T](fun : PartialFunction[R,T]) : Wrapper[R, T] = new Wrapper(fun)


val f : PartialFunction[String, Int] = {
  case "bingo" => 0
}

def testFF(x : String) : Unit = x match {
  case f.PartialExtractor(i) => println(i)
  case _ => println("nothing")
}

Update

The best I could think of:

def testInplace(x : String) : Unit ={
  val ff = { case "bingo" => 0 } : PartialFunction[String, Int]
  x match {
   case ff.PartialExtractor(Test(i)) => println(i)
   case "sd" => println("nothing") }
}
like image 200
Archeg Avatar answered Dec 11 '25 15:12

Archeg



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!