2011-01-29 16 views
34

estoy viendo Runar Bjarnason present Functional Programming for Beginners, a las 14:45 y se define un método:Funciones vs métodos en Scala

def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0 

y una función:

val isEven = isDivisibleBy(2) 

¿Cuáles son los pros y los contras de la definición isEven como una función en lugar de un método?

He leído Scala Functions vs Methods, así como Difference between method and function in Scala, y entiendo las diferencias semánticas, pero me pregunto si hay alguna razón más profunda en este caso ¿por qué función podría o no podría ser preferible al uso de un método:

def isEven = isDivisibleBy(2) 
+0

Sólo pensar en ello en el equivalente Java (las funciones vs. Métodos hace un buen trabajo de ese Scala) y cómo encaja en el tiempo de ejecución. Esa es una buena parte de la razón de un enfoque sobre el otro. También tenga en cuenta que el alcance de 'def' es importante ya que no es el mismo en todas partes (es solo un" método "- detalles de implementación aparte - a nivel de clase). –

Respuesta

46

Debajo del capó, hay otras diferencias entre funciones y métodos. En general, un método simple genera menos sobrecarga que una función (que técnicamente es un objeto con un método apply).

Sin embargo, si se trata de no preocuparse por esas diferencias y pensar en def, val y var como campos con una semántica diferente, entonces es simplemente que def evalúa cada vez que se llama a val mientras evalúa sólo una vez.

Por lo tanto, un val isEven = isDivisibleBy(2) debe llamar a isDivisibleBy(2) durante su definición y asignar el resultado de isDivisibleBy(2). P.ej. que sustituye a la k en

def isDivisibleBy(k: Int): Int => Boolean = i => i % k == 0 

con 2 y asigna el resultado de la expresión final (en este caso sólo hay una expresión):

val isEven: Int => Boolean = i => i % 2 == 0 

def isEven por otra parte no hace tal evaluación y da como resultado una llamada a isDivisibleBy (2) cada vez.

Eso significa que, más tarde, cuando se ejecuta el código, isEven(11) genera en caso de una val

11 % 2 == 0 

y en el caso de un def, tendrá

isDivisibleBy(2)(11) 

y sólo después de evaluando isDivisibleBy obtendrá el resultado.

Usted puede añadir algo de código de depuración para isDivisibleBy para ver la diferencia:

def isDivisibleBy(k: Int): Int => Boolean = { 
    println("evaluating isDivisibleBy") 
    i => i % k == 0 
} 
+1

¿Qué hay de la diferencia entre 'def' en el nivel de clase y vs' def' dentro de un método? +1 ya que es una buena respuesta (aunque cada vez que se aplica una función, por ejemplo, en un 'val' se llamará, es solo un detalle de que los métodos pueden invocarse sin parens explícitos), pero sería bueno para capturar esas diferencias (y el significado de "método") también. –

+0

pregunta tonta: ¿qué hace 'Boolean =' allí? Soy nuevo en Scala. :) – DavidLin

+0

¿Esto significa que llamar a la función isEven será más rápido puede llamar al método isEven? ¿Esta es la ventaja de las funciones sobre los métodos? –

5

Creo que el principal profesional para definir la función isEven como val es mostrar al público que la función se puede definir de esta manera. Entonces está claro, que una función es solo un objeto como todo lo demás en Scala. Pero en el mundo de la programación no demostrativa, no es necesario escribir funciones como val s.

+0

No es una definición de función sino una aplicación de un método con un resultado de función: muestra que una función (Int => Boolean) se puede almacenar/tratar como un objeto normal. 'val square = (x) => x * x' sería una definición, que también muestra lo mismo. Los sutiles matices entre los dos (** métodos que están ligados a un objeto y permiten la sobrecarga y anulación ** (en términos de Java) y ** las funciones que no son métodos **) se convierten en "interesantes". –

+0

Tengo una vaga comprensión de lo que es 'function definition', porque es bastante difícil de google :-), así que lo estoy usando de una manera intuitiva. ¿Cómo es 'val square ...' diferente? También acepta un argumento y crea una función que devuelve un objeto aplicando el método '*' a 'x'. Traté de leer la pregunta a fondo y responder a esta pregunta en particular. "en este caso" es crucial, la pregunta es mencionar a un hombre hablando en la presentación y su punto era que para mostrar una forma diferente de "tratar" los métodos/funciones, la pregunta no era sobre los matices entre el método y el objeto funcional. – coubeatczech

+0

Un método si un artefacto de Java (quizás Scala los tendría si no fuera parte de Java) - los objetos tienen * métodos * (estos se definen con 'def' en el nivel de clase). Las funciones en Scala son solo una forma especial de un objeto (ver FunciónN, etc.) que tienen un método 'apply' (' def' dentro de una función son * no métodos * - en realidad, se pueden/se implementan como tales, pero eso es un detalle de implementación ya que esto no está expuesto).Scala simplemente convierte un * método * en una * función * (o almacena una * función * en una variable) trivial. No he visto esta distinción abordada en ninguna respuesta. –

3

El método def isDivisibleBy(k: Int): Int => Boolean devuelve una función que toma un Int (i) como parámetro y devuelve un valor booleano (i % k == 0).

val isEven = isDivisibleBy(2) por el contrario es un campo en el que se almacena la función devuelta por isDivisibleBy(2). Si usa def en lugar de val, se invocará el método isDivisibleBy cada vez que se llame al método isEven, pero ahora se llama solo una vez y el resultado se almacena en el campo.

que podría lograr el mismo resultado escribiendo def isEven(i: Int): Boolean = i % 2 == 0

creo que el objetivo de este ejemplo es que se puede tener funciones que devuelven otras funciones, y puede almacenar las funciones como objetos, y luego llamar a ellos como si fueron métodos tradicionalmente definidos. El código anterior también es bastante similar a currying, por lo que también podría ser una cosa demostrada por el ejemplo (aunque no utiliza Scala's syntax for currying).

+0

Con currying parece ser un poco más lento, no sé por qué. – Debilski

13

Me gustaría abordar otro punto aquí. Esto define como un método isEven:

def isEven = isDivisibleBy(2) 

Y esto define isEven como un método así:

val isEven = isDivisibleBy(2) 

En ambos casos, isEven es un método que, cuando se le llama, el retorno de una función.

En el primer caso, se llama isDivisible(2) cada vez que se llama isEven. Por ejemplo, esto exige isDivisible(2) tres veces:

def isEven = isDivisibleBy(2) 
List(1,2,3).filter(isEven) 

En el segundo caso, isDivisible(2) se llama una vez (en el momento de la construcción, o cuando se ejecuta esa línea en una definición), y ese valor se recupera cada vez isEven es llamado. El ejemplo siguiente se llama isDivisible(2) una sola vez:

val isEven = isDivisibleBy(2) 
List(1,2,3).filter(isEven) 
+3

Hasta donde yo sé, 'val' no define un método. Tal vez te refieres a que está traducido a un método en código byte de Java por alguna razón (aunque no veo por qué sería ese el caso). Yo pensaría que es simplemente una referencia al objeto función. Después de todo, puedes pasar la referencia como con otros objetos. – herman