2010-05-05 15 views
28
def foo(x:Int, f:Unit=>Int) = println(f()) 

foo(2, {Unit => 3+4} 

//case1 
def loop:Int = 7 
foo(2, loop) //does not compile 

changing loop to 
//case 2 
def loop():Int = 7 
foo(2, loop) // does not compile 

changing loop to 
//case 3 
def loop(x:Unit): Int = 7 //changing according to Don's Comments 
foo(2,loop) // compiles and works fine 

should'nt case 1 and case 2 also work? ¿Por qué no están trabajando?Funciones sin argumentos, con unidad como argumento en scala

definir como foo

def foo(x:Int, y:()=>Int) 

continuación, caso 2 funciona pero no el caso 1.

Arent todos ellos supone que trabajan, la definición de las funciones de cualquier manera.

// también creo que() => Int in foo es un mal estilo, y: => Int no funciona, ¿comentarios?

+2

def define los métodos (que no son de primera clase), no las funciones (que * son * de primera clase). La aplicación parcial eleva los métodos a las funciones cuando los necesita. –

+1

Puede por favor elaborar ... No lo conseguí. ¿Quiso decir que la def no se puede pasar? es decir, ¿el "bucle" anterior no se puede pasar a otras funciones? – scout

+2

Correcto. Cuando decimos "primera clase" nos referimos al mismo estado que cualquier otro valor, como un Int, una Cadena o una instancia de alguna clase definida por el usuario. Los métodos no se pueden tratar de esta manera (solo se pueden llamar). Las funciones, por otro lado (que son instancias de (subclases de) FunctionN (N es el número de argumentos)), son entidades de primera clase por la razón obvia de que son instancias de una clase. –

Respuesta

74

Scala distingue entre las siguientes cosas:

  • Funciones/métodos con no hay listas de parámetros ("por parámetro -name" si una función)
  • Funciones con una lista de parámetros vacía
  • Funciones con un parámetro de la unidad Tipo de

Ninguno de estos son equivalentes, aunque para su conveniencia Scala que permite para elide listas de parámetros vacías. (Por cierto, dos listas de parámetros vacío tampoco son lo mismo).

Así, a pesar de que está escrito Unit(), esto es no el mismo que el argumento de la función parens () para una función o método. En cambio, piense en () como Tuple0.

lo tanto, si usted dice f: Unit => Int, lo que quiere decir es "f toma un parámetro, pero es un parámetro muy aburrido porque es Unit, que debe ser siempre el mismo valor Tuple0 aburrido ()". Lo que estás escribiendo es realmente corto para f: (Unit) => Int.

Si dice f:() => Int, quiere decir que "f no toma parámetros y produce un Int".

Si dice f: => Int, quiere decir que "demorar la ejecución de cualquier instrucción produce un valor Int hasta que lo usemos en este código (y lo volvamos a evaluar cada vez)". Funcionalmente, esto acaba siendo básicamente el mismo que f:() => Int (y se convierte internamente en la misma clase Function0), pero tiene un uso diferente, presumiblemente para permitir una forma más compacta de cierres (siempre se omite el => en el código de llamada))

+0

Así que si tengo una función def loop() = 7 Realmente no tiene sentido para mí insertar la unidad, como en def loop (x: Unit) = 7, si quiero pasarlo a otra función como foo arriba. – scout

+2

@Scout: no hay ninguna razón para agregar una "Unidad" superflua en ese caso. Es útil para la abstracción. Supongamos que tiene una función de composición: 'def comp [A, B, C] (f: A => B, g: B => C, a: A) = g (f (a))' e intenta pasar es una 'f' que no devuelve un valor. ¿Ahora que haces? Bueno, resulta que Scala siempre _desea_ devolver algo - al menos '()' (el único valor posible de tipo 'Unidad'). Entonces ahora puedes escribir una 'g' que toma una entrada de tipo' Unidad' y usa la función de composición general anterior. Pero para la mayoría de las situaciones, solo use 'def f() = ...' o 'def f = ...'. –

+1

Gracias por la aclaración. Estaba intentando descubrir cómo hacer la evacuación perezosa. Tenga en cuenta que el espacio entre ':' y '=' en 'f: => Int' es importante. – Jus12

14

() => Int es Function0 [Int] mientras que la Unidad => Int es Función1 [Unidad, Int]

scala> val function0:() => Int =() => 5 
function0:() => Int = <function0> 

scala> val function1: Unit => Int = u => 5 
function1: (Unit) => Int = <function1> 

scala> function0() 
res0: Int = 5 

scala> function1("anything") 
res1: Int = 5 

scala> function1(100) 
res2: Int = 5 

scala> 

en cuenta también que() es un objeto de la Unidad de

scala> function1(()) 
res11: Int = 5 

scala> function1() 
res12: Int = 5 

scala> function1() 
res13: Int = 5 

scala> val unit =() 
unit: Unit =() 


scala> function1(unit) 
res15: Int = 5 

scala> function1 apply unit 
res16: Int = 5 

scala> 
+0

scala> val function1: Unit => Int = Unit => 5 Tenga en cuenta que en esta línea, la última "Unidad" no es un identificador de tipo, sino solo un nombre para el parámetro (puede cambiarlo a "x" por ejemplo). –

+0

@Dimitris Andreou: Sí, tienes razón. – Eastsun

+0

Obtengo por qué 'function1 (())' y 'function1()' funciona, pero no entiendo por qué 'function1()' funciona. Esperaría que esto siguiera las reglas de invocación de método típicas en Scala, es decir, necesitarías el espacio después del nombre de la función, o el valor de la unidad entre el parámetro parens ... – ThaDon

2

En el caso 1 y 2 anteriores, el valor de retorno de bucle en lugar de bucle en sí es de tipo comprobado para el segundo argumento a foo y falla: Int = Unidad => Int

El cambio a loop tiene un error tipográfico.

Cuestiones relacionadas