useful name metatags keywords etiquetas ejemplos scala functional-programming scala-2.8

scala - name - ¿El diseño de PartialFunction es ineficiente?



metatags (1)

Hay una conversación sobre esto ahora mismo en la lista de correo de scala-internals . Martin Odersky ha sugerido un nuevo tipo: FunctionWithDefault . Martin habla no solo de una penalización de tiempo de ejecución, sino también de una penalización en tiempo de compilación (de hinchazón de archivo de clase) al usar PartialFunction :

Primero, necesitamos generar el código de coincidencia de patrón dos veces, una vez en la aplicación y luego otra vez en isDefinedAt. Segundo, también necesitamos ejecutar el código dos veces, primero para probar si la función es aplicable, y luego para aplicarla realmente.

La respuesta a su pregunta es esencialmente "sí" y este comportamiento (de PartialFunction ) no cambiará debido a problemas de compatibilidad con versiones anteriores (por ejemplo, ¿qué isDefinedAt si isDefinedAt tiene efecto secundario?).

El nuevo tipo propuesto, FunctionWithDefault no tiene isDefinedAt y tiene un método:

trait FunctionWithDefault[-I, +O] { def applyOrElse[OO >: O](i : I, default : I => OO) : OO }

que actúa un poco como el método de Option s getOrElse .

Tengo que decir que, como de costumbre, no puedo imaginar que esta ineficiencia presente algún tipo de problema de rendimiento en la abrumadora mayoría de los casos.

Esto es algo que me he preguntado por un tiempo. Veo este patrón mucho:

if (pf.isDefinedAt(in)) pf(in)

Al dividir esto en dos llamadas separadas, todos los patrones que se evaluaron en #isDefinedAt también se evalúan en #apply. Por ejemplo:

object Ex1 { def unapply(in: Int) : Option[String] = { println("Ex1") if (in == 1) Some("1") else None } } object Ex2 { def unapply(in: Int) : Option[String] = { println("Ex2") if (in == 2) Some("2") else None } } val pf : PartialFunction[Int,String] = { case Ex1(result) => result case Ex2(result) => result } val in = 2 if (pf.isDefinedAt(in)) pf(in)

Qué impresiones

Ex1 Ex2 Ex1 Ex2 res52: Any = 2

En el peor de los casos, donde el patrón coincide con el último, ha evaluado sus patrones / extractores dos veces cuando llama a una función parcial. Esto podría volverse ineficiente cuando se combina con extractores personalizados que hicieron más que una simple coincidencia de patrón de clase o lista (por ejemplo, si tenía un extractor que analizaba un documento XML y devolvía algunos objetos de valor)

PartialFunction # lift sufre de la misma doble evaluación:

scala> pf.lift(2) Ex1 Ex2 Ex1 Ex2 res55: Option[String] = Some(2)

¿Hay alguna manera de llamar condicionalmente una función si está definida sin llamar potencialmente a todos sus extractores dos veces?