2011-04-28 7 views
7

Tengo esta situación extraña que no entiendo. Estoy leyendo el libro "Programación en Scala", cap. 9.Cosas raras con función al curry

Digamos que tengo una función al curry:

def withThis(n:Int)(op:Int=>Unit){ 
     println("Before") 
     op(n); 
     println("After") 
} 

Cuando lo llamo con un argumento dentro de un rizado-sintaxis especial funciona como se esperaba:

withThis(5){ 
    (x) => {println("Hello!"); println(x); } 
} 
// Outputs 
Before 
Hello! 
5 
After 

Sin embargo, si poner dos declaraciones, obtengo algo extraño:

withThis(5){ 
    println("Hello!") 
    println(_) 
} 
// Outputs 
Hello! 
Before 
5 
After 

¿Cómo es que "¡Hola!" se imprime antes de "Antes" y luego se imprime "5" en el interior? ¿Estoy loco?

Respuesta

10

Su último ejemplo de código debe ser reescrita como sigue para producir el resultado esperado:

withThis(5) { x => 
    println("Hello!") 
    println(x) 
} 

lo contrario, su ejemplo es equivalente al

withThis(5) { 
    println("Hello!") 
    (x: Int) => println(x) 
} 

como el marcador de posición _ será ampliado para enlazar lo más estrechamente posible de una forma no degenerada (es decir, no se expandiría a println(x => x)).

La otra cosa a tener en cuenta es que un bloque siempre devuelve su último valor. En su ejemplo, el último valor es en realidad (x: Int) => println(x).

+2

Pero println (x => x) ni siquiera es la sintaxis correcta. En cualquier caso, entiendo lo que println (_) hace, era más confuso en cuanto a este negocio de "bloqueos". – drozzy

+0

La sintaxis es correcta. No compilaría en este caso debido al tipo de parámetro faltante, pero funcionaría si el compilador pudiera inferirlo. Ejemplo trivial: 'def doit (f: Int => Int) =(); doit (x => x) ' –

+0

Sé que es equivalente" (x: Int) => println (x) ", mi pregunta es por qué realmente ejecuta println primero. Supongo que respondiste con "bloquear siempre devuelve el último valor". ¿Esto significa que los bloques no se evalúan de forma perezosa? – drozzy

3

En su segundo ejemplo, la parte en curlies: { println("Hello!"); println(_) } es un bloque que imprime "¡Hola!" y devuelve un currículum println. Imagínese simplificado como { println("Hello!"); 5 }, un bloque que imprime "¡Hola!" y devuelve 5.

+0

No creo que haya llegado a la parte de "bloques" en el libro todavía. Es por eso que estoy confundido, probablemente. – drozzy

+0

Entonces, ¿no hay forma de hacerlo funcionar como se espera en el segundo ejemplo? Intenté con los parámetros de nombre-por-pero no toman un argumento. – drozzy

+0

Solo para ser quisquilloso: el bloque no devuelve un '' curry' println' ", sino una función anónima con un argumento que llama a println con el argumento que obtiene. –

Cuestiones relacionadas