Question

I occasionally come across the following pattern, where I essentially have a PartialFunction[SomeType,AnotherType], and want to treat it as a Function[SomeType,Option[AnotherType], eg:

def f(s:SomeType):Option[AnotherType] = s match {
  case s1:SubType1 => Some(AnotherType(s1.whatever))
  case s2:SubType2 => Some(AnotherType(s2.whatever))
  case _ => None
}

Is there a way to write the above function in a way that avoids the default case and wrapping the result in Some where it's defined? The best I've come up with so far is this:

def f(s:SomeType):Option[AnotherType] = pf.lift(s)
def pf:PartialFunction[SomeType,AnotherType] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}

Is there a way to do it without defining an intermediate function? I've already tried various things along the lines of the following, but haven't got anything to compile yet:

def f:Function[SomeType,Option[AnotherType]] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}.lift
Was it helpful?

Solution

condOpt in object scala.PartialFunction. From the scaladoc:

def onlyInt(v: Any): Option[Int] = condOpt(v) { case x: Int => x }

OTHER TIPS

Not so much an answer, as an explanation of why huynhjl's answer is correct...

Part of your confusion is that you're trying to def a partial function. All this does is to create a method that returns a PartialFunction object, when you may as well create the thing directly:

val pf: PartialFunction[SomeType,AnotherType] = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
}

Though I personally prefer to use type ascription:

val pf = {
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
} : PartialFunction[SomeType,AnotherType]

Either way, you have to specify what the input type is, so you have to give the exact signature of the PartialFunction. I know it feels like it should be possible to to infer this but, alas, that is sadly not the case!

Using the ascribed version, you can then define and lift all in the same place:

val pf = ({
  case s1:SubType1 => AnotherType(s1.whatever)
  case s2:SubType2 => AnotherType(s2.whatever)
} : PartialFunction[SomeType,AnotherType]).lift

PartialFunction.condOpt is the better solution though, as it allows the inferencer to do most of this work for you, leaving much cleaner code :)

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top