renault - scala vs java
Componer y luego métodos (4)
Bien, 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íciles de explicar, pero, básicamente, la función "comenzará" en el delimitador de expresión más interno. 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, así es como 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 lo que intentó con el parámetro -Ytyper-debug
.
Estoy siguiendo el tutorial Patrón de coincidencia y composición funcional en los métodos Scala compose
y andThen
. Hay un ejemplo:
scala> def addUmm(x: String) = x + " umm"
scala> def addAhem(x: String) = x + " ahem"
val ummThenAhem = addAhem(_).compose(addUmm(_))
Cuando intento usarlo obtengo 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?
Creo que el tutorial fue escrito para una versión anterior de Scala (probablemente 2.7.7 o anterior). Desde entonces, se han producido algunos cambios en el compilador, a saber, las extensiones del sistema de tipos, que ahora provocan que el tipo de inferencia falle en:
addUhum(_).compose(addAhem(_))
El levantamiento de una función aún funciona con esa sintaxis si solo escribe:
addUhum(_)
De la documentación compose
:
Compone dos instancias de Función1 en una nueva Función1, con esta función aplicada al último.
entonces debes escribir
scala> val ummThenAhem = (addAhem _).compose(addUmm _)
ummThenAhem: String => java.lang.String = <function1>
para tratar addAhem
y addUmm
como funciones parcialmente aplicadas (es decir, function1
)
scala> addAhem _
res0: String => java.lang.String = <function1>
addAhem
es un método. compose
método de compose
se define en las funciones. addAhem _
convierte addAhem
del método en función, por lo que se puede addAhem
a compose
en él. 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 addUmm _
porque el compilador puede convertir automáticamente un método en una función cuando sabe que una función se espera de todos modos). Entonces tu código:
addAhem _ compose addUmm
es lo mismo que
(addAhem _).compose(addUmm)
pero no
addAhem(_).compose(addUmm(_))
PD. No miré el enlace que proporcionaste.