2011-09-21 15 views
42

estoy siguiendo el tutorial Pattern matching & functional composition sobre el Scala compose y andThen métodos. Hay un ejemplo:componer y andthen métodos

scala> def addUmm(x: String) = x + " umm" 
scala> def addAhem(x: String) = x + " ahem" 

val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Cuando trato de usarlo me sale un error:

<console>:7: error: missing parameter type for expanded function ((x$1) => addAhem(x$1).compose(((x$2) => addUmm(x$2)))) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
          ^
<console>:7: error: missing parameter type for expanded function ((x$2) => addUmm(x$2)) 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 
              ^
<console>:7: error: type mismatch; 
found : java.lang.String 
required: Int 
    val ummThenAhem = addAhem(_).compose(addUmm(_)) 

Sin embargo, esto funciona:

val ummThenAhem = addAhem _ compose addUmm _ 

o incluso

val ummThenAhem = addAhem _ compose addUmm 

¿Qué pasa con el código en el tutorial? ¿No es la última expresión la misma que la primera sin paréntesis?

Respuesta

38

addAhem es un método El método compose se define en las funciones. addAhem _ convierte addAhem del método a la función, por lo que se puede llamar a compose. compose espera una función como argumento. Le está dando un método addUmm convirtiendo addUmm en una función con addUmm _ (El guión bajo puede omitirse porque el compilador puede convertir automáticamente un método en una función cuando sabe que se espera una función). Por lo que su código:

addAhem _ compose addUmm 

es la misma que

(addAhem _).compose(addUmm) 

pero no

addAhem(_).compose(addUmm(_)) 

PS no me veía en el enlace que ya ha proporcionado.

+0

Por el bien de la integridad, el ejemplo andthen se parece a:.. 'val ahemThenUmm = addAhem (_) andthen (addUmm (_))' cuando debería parecerse a 'val ahemThenUmm1 = (addAhem _) andthen (addUmm) ' –

+0

No estoy tan seguro de la parte escrita entre corchetes; el compilador * no * convierte el método para que funcione automáticamente, al menos para Scala 2.10.2. La solución es declarar 'addAhem' y' addUmm' como funciones para que 'compose' o' andThen' funcione sin '_'. –

5

De compose documentación:

Composes two instances of Function1 in a new Function1, with this function applied last.

por lo que debe escribir

scala> val ummThenAhem = (addAhem _).compose(addUmm _) 
ummThenAhem: String => java.lang.String = <function1> 

para tratar addAhem y addUmm funciona como parcialmente aplicadas (es decir function1)

scala> addAhem _ 
res0: String => java.lang.String = <function1> 
2

Creo que el tutorial fue escrito para una versión anterior de Scala (probablemente 2.7.7 o anterior). Ha habido algunos cambios en el compilador desde entonces, es decir, extensiones para el sistema de tipos, que ahora hacen que el tipo de inferencia que falle en el:

addUhum(_).compose(addAhem(_)) 

La elevación a una función todavía funciona con la sintaxis si sólo escribir:

addUhum(_) 
45

Bueno, esto:

addUhum _ 

es una expansión eta. Convierte métodos en funciones.Por otro lado, esto:

addUhum(_) 

es una función anónima. De hecho, es una aplicación de función parcial, ya que este parámetro no se aplica y todo se convierte en una función. Se expande a:

x => addUhum(x) 

Las reglas exactas para la expansión son un poco difícil de explicar, pero, básicamente, la función "Inicio" en el delimitador de expresión más íntima. La excepción son las aplicaciones de función parcial, donde la "x" se mueve fuera de la función - si se usa _ en lugar de un parámetro.

De todos modos, esta es la forma en que se expande:

val ummThenAhem = x => addAhem(x).compose(y => addUmm(y)) 

Por desgracia, el tipo inferencer no sabe el tipo de x o y. Si lo desea, puede ver exactamente qué intentó con el parámetro -Ytyper-debug.

Cuestiones relacionadas