2011-07-26 7 views
5

¿Hay alguna forma rápida de usar como una función concreta (de tipo, por ejemplo, (A) => B) como PartialFunction[A, B]? La sintaxis más concisa que conozco es:Scala PartialFunctions from concrete

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

¿Hay una conversión implícita en cualquier lugar, algo así como:

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

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

} 

supongo que acabo de escribir lo que estaba buscando, pero esto ya existe en las bibliotecas de Scala?

Respuesta

5

Hacer esto con una conversión implícita es peligroso, por la misma razón que (A) => B no debe heredar de PartialFunction[A, B]. Es decir, el contrato de PartialFunction garantiza que puede * llamar sin problemas a apply donde isDefinedAt devuelva true. El contrato de Function1 no ofrece tal garantía.

Su conversión implícita dará como resultado una función parcial que infringe su contrato si la aplica a una función que no está definida en todas partes. En su lugar, utilice un proxeneta para hacer la conversión explícita:

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 

* Como se ha discutido en los comentarios, puede que no sea del todo claro qué "seguridad" significa aquí. La forma en que lo pienso es que una función parcial declara explícitamente su dominio en el siguiente sentido preciso: si isDefinedAt devuelve verdadero para un valor x, entonces apply(x) se puede evaluar de manera coherente con la intención del autor de la función. Que no implica que apply(x) no lanzará una excepción, sino simplemente que la excepción fue parte del diseño de la función (y debe documentarse).

+0

Gracias; Tuve la idea errónea de que Function1 implicaba estar definido en todo el dominio. –

+0

@AaronNovstrup: su explicación del contrato de PartialFunction es la única que tiene sentido, pero ScalaDocs no lo refleja (al menos hasta 2.9.1). Los ScalaDocs de 'PartialFunction' afirman que:" Una función parcial de tipo 'PartialFunction [A, B]' es una función unaria donde el dominio no incluye necesariamente todos los valores de tipo 'A'. " Además, nunca afirman que sea seguro (en qué sentido) llamar a f donde sea que se haya definido, y eso es bastante fácil de violar, como lo hace el literal 'PartialFunction' literal' {case 0 => 1/0} '. ¿De dónde sacaste esa información? ¿Se debe presentar un informe de error? – Blaisorblade

+0

@Blaisorblade Creo que leí esta explicación en la lista de correo cuando estaba aprendiendo Scala (ha pasado un tiempo), y no estaba mirando ninguna documentación cuando escribí esta respuesta. Y, sí, es fácil e incluso algo común violar este contrato (por ejemplo, para envolver/volver a lanzar una excepción en un bloque catch). El verdadero punto es que las funciones parciales definen su dominio, mientras que las funciones comunes no lo hacen (con cierta falta de claridad sobre lo que realmente significa). –

0

No, intenté encontrar uno hace unos meses y terminé escribiendo el mío que es esencialmente el mismo que el tuyo.

+0

Me parece que '(A) => B' debe heredar de' PartialFunction [A, B] ', y no al revés. –

+1

Estoy de acuerdo con eso, en razón de que una Función (total) es una función Parcial que se define en todas partes (isDefinedAt (x) = true). Sin embargo, Martin Odersky dice que no se garantiza que una Función sea una Función total, solo que su dominio no está documentado. Entonces, una función parcial es una función que documenta su dominio. –

+0

http://www.scala-lang.org/node/2750 –