Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala PartialFunctions from concrete ones

Is there any quick way to use as a concrete function (of type, say, (A) => B) as a PartialFunction[A, B]? The most concise syntax I know of is:

(a: A) => a match { case obj => func(obj) }

Is there an implicit conversion anywhere, something like:

implicit def funcAsPartial[A, B](func: A => B) = new PartialFunction[A, B] {

  def isDefinedAt(a: A) = true
  def apply(a: A) = func(a)

}

I guess I just wrote what I was looking for, but does this already exist in the Scala libraries?

like image 515
Kenneth Allen Avatar asked Jul 26 '11 17:07

Kenneth Allen


1 Answers

Doing this with an implicit conversion is dangerous, for the same reason that (A) => B should not inherit from PartialFunction[A, B]. That is, the contract of PartialFunction guarantees that you can safely* call apply wherever isDefinedAt returns true. Function1's contract provides no such guarantee.

Your implicit conversion will result in a PartialFunction that violates its contract if you apply it to a function that is not defined everywhere. Instead, use a pimp to make the conversion explicit:

implicit def funcAsPartial[A, B](f: A => B) = new {
   /** only use if `f` is defined everywhere */
   def asPartial(): PartialFunction[A, B] = {
      case a => f(a)
   }

   def asPartial(isDefinedAt: A => Boolean): PartialFunction[A, B] = {
      case a if isDefinedAt(a) => f(a)
   }
}

// now you can write
val f = (i: Int) => i * i

val p = f.asPartial // defined on all integers
val p2 = f.asPartial(_ > 0) // defined only on positive integers

* As discussed in the comments, it may not be entirely clear what "safety" means here. The way I think about it is that a PartialFunction explicitly declares its domain in the following precise sense: if isDefinedAt returns true for a value x, then apply(x) can be evaluated in a way that is consistent with the intent of the function's author. That does not imply that apply(x) will not throw an exception, but merely that the exception was part of the design of the function (and should be documented).

like image 113
Aaron Novstrup Avatar answered Nov 22 '22 07:11

Aaron Novstrup