superior orden funciones ejemplos scala

orden - Funciones vs métodos en Scala



funciones de orden superior (4)

Estoy viendo a Runar Bjarnason presentar la Programación Funcional para Principiantes , ya las 14:45 él define un método:

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 definir isEven como una función en lugar de un método?

He leído Scala Functions vs Methods así como Diferencia entre método y función en Scala , y entiendo las diferencias semánticas, pero me pregunto si hay alguna razón más profunda en este caso por qué una función puede o no ser preferible a usar un método:

def isEven = isDivisibleBy(2)


Creo que el principal profesional para definir la función es isEven como val es mostrarle a la audiencia 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 .


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

Sin embargo, si intenta no preocuparse por esas diferencias y piensa en def , val y var como campos con semántica diferente, entonces es simplemente que def evalúa cada vez que se llama, mientras que val evalúa solo una vez.

Entonces, un val isEven = isDivisibleBy(2) debe llamar a isDivisibleBy(2) durante su definición y asignar el resultado de isDivisibleBy(2) . Por ejemplo, reemplaza 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 solo hay una expresión):

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

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

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

11 % 2 == 0

y en caso de def , tendrás

isDivisibleBy(2)(11)

y solo después de evaluar isDivisibleBy obtendrás el resultado.

Puede agregar un código de depuración a isDivisibleBy para ver la diferencia:

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


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

val isEven = isDivisibleBy(2) por otro lado es un campo en el que se almacena la función devuelta por isDivisibleBy(2) . Si usa def 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.

Puede obtener el mismo resultado escribiendo def isEven(i: Int): Boolean = i % 2 == 0

Creo que el objetivo del ejemplo es que puede tener funciones que devuelven otras funciones, y puede almacenar las funciones como objetos y luego llamarlas como si fueran métodos definidos tradicionalmente. El código anterior también es bastante similar al currying , por lo que también podría ser una cosa demostrada por el ejemplo (aunque no utiliza la sintaxis de Scala para currying ).


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

def isEven = isDivisibleBy(2)

Y esto también se define como un método:

val isEven = isDivisibleBy(2)

En ambos casos, isEven es un método que, cuando se llama, devuelve una función.

En el primer caso, se isDivisible(2) cada vez que se llama a isEven . Por ejemplo, esta llamada es isDivisible(2) tres veces:

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

En el segundo caso, se isDivisible(2) 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 que se llama a isEven . Las siguientes llamadas de ejemplo son isDivisible(2) única vez:

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