No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

High Order functions

29/37
Recursos

Aportes 16

Preguntas 5

Ordenar por:

¿Quieres ver más aportes, preguntas y respuestas de la comunidad?

o inicia sesión.

Funciones de orden superior

Kotlin es un lenguaje orientado a objetos pero introduce características existentes en los lenguajes funcionales que nos permiten crear un código más claro y expresivo.

Una de las características del paradigma de la programación funcional son las funciones de orden superior.

Las funciones de orden superior son funciones que pueden recibir como parámetros otras funciones y/o devolverlas como resultados.

Veremos una serie de ejemplos muy sencillos para ver como Kotlin implementa el concepto de funciones de orden superior y a medida que avancemos en el curso podremos ver las ventajas de este paradigma.

Problema 1
Definir una función de orden superior llamada operar. Llegan como parámetro dos enteros y una función. En el bloque de la función llamar a la función que llega como parámetro y enviar los dos primeros parámetros.
La función retorna un entero.

Proyecto147 - Principal.kt

fun operar(v1: Int, v2: Int, fn: (Int, Int) -> Int) : Int {
    return fn(v1, v2)
}

fun sumar(x1: Int, x2: Int) = x1 + x2

fun restar(x1: Int, x2: Int) = x1 - x2

fun multiplicar(x1: Int, x2: Int) = x1 * x2

fun dividir(x1: Int, x2: Int) = x1 / x2

fun main(parametro: Array<String>) {
    val resu1 = operar(10, 5, ::sumar)
    println("La suma de 10 y 5 es $resu1")
    val resu2 = operar(5, 2, ::sumar)
    println("La suma de 5 y 2 es $resu2")
    println("La resta de 100 y 40 es ${operar(100, 40, ::restar)}")
    println("El producto entre 5 y 20 es ${operar(5, 20, ::multiplicar)}")
    println("La división entre 10 y 5 es ${operar(10, 5, ::dividir)}")
}

Tenemos definidas 6 funciones en este problema. La única función de orden superior es la llamada “operar”:

fun operar(v1: Int, v2: Int, fn: (Int, Int) -> Int) : Int {
    return fn(v1, v2)
}

El tercer parámetro de esta función se llama “fn” y es de tipo función. Cuando un parámetro es de tipo función debemos indicar los parámetros que tiene dicha función (en este caso tiene dos parámetros enteros) y luego del operador -> el tipo de dato que retorna esta función:

fn: (Int, Int) -> Int

Cuando tengamos una función como parámetro que no retorne dato se indica el tipo Unit, por ejemplo:

fn: (Int, Int) -> Unit

El algoritmo de la función operar consiste en llamar a la función fn y pasar los dos enteros que espera dicha función:

return fn(v1, v2)

Como la función operar retorna un entero debemos indicar con la palabra clave return que devuelva el dato que retorna la función “fn”.

Las cuatro funciones que calculan la suma, resta, multiplicación y división no tienen nada nuevo a lo visto en conceptos anteriores:

fun sumar(x1: Int, x2: Int) = x1 + x2

fun restar(x1: Int, x2: Int) = x1 - x2

fun multiplicar(x1: Int, x2: Int) = x1 * x2

fun dividir(x1: Int, x2: Int) = x1 / x2

En la función main llamamos a la función operar y le pasamos tres datos, dos enteros y uno con la referencia de una función:

val resu1 = operar(10, 5, ::sumar)

Como vemos para pasar la referencia de una función antecedemos el operador ::
La función operar retorna un entero y lo almacenamos en la variable resu1 que mostramos luego por pantalla:

println("La suma de 10 y 5 es $resu1")

Es importante imaginar el funcionamiento de la función operar que recibe tres datos y utiliza uno de ellos para llamar a otra función que retorna un valor y que luego este valor lo retorna operar y llega finalmente a la variable “resu1”.

Llamamos a operar y le pasamos nuevamente la referencia a la función sumar:

val resu2 = operar(5, 2, ::sumar)
println("La suma de 5 y 2 es $resu2")

De forma similar llamamos a operar y le pasamos las referencias a las otras funciones:

println("La resta de 100 y 40 es ${operar(100, 40, ::restar)}")
println("El producto entre 5 y 20 es ${operar(5, 20, ::multiplicar)}")
println("La división entre 10 y 5 es ${operar(10, 5, ::dividir)}")

Tener en cuenta que para sumar dos enteros es mejor llamar directamente a la función sumar y pasar los dos enteros, pero el objetivo de este problema es conocer la sintaxis de las funciones de orden superior presentando el problema más sencillo.

Las funciones de orden superior se pueden utilizar perfectamente en los métodos de una clase.

Problema 2

Declarar una clase que almacene el nombre y la edad de una persona. Definir un método que retorne true o false según si la persona es mayor de edad o no. Esta función debe recibir como parámetro una función que al llamarla pasando la edad de la persona retornara si es mayor o no de edad.
Tener en cuenta que una persona es mayor de edad en Estados Unidos si tiene 21 o más años y en Argentina si tiene 18 o más años.

Proyecto148 - Principal.kt

class Persona(val nombre: String, val edad: Int) {
    fun esMayor(fn:(Int) -> Boolean): Boolean {
        return fn(edad)
    }
}

fun mayorEstadosUnidos(edad: Int): Boolean {
    if (edad >= 21)
        return true
    else
        return false
}

fun mayorArgentina(edad: Int): Boolean {
    if (edad >= 18)
        return true
    else
        return false
}

fun main(parametro: Array<String>) {
    val persona1 = Persona("juan", 18)
    if (persona1.esMayor(::mayorArgentina))
        println("${persona1.nombre} es mayor si vive en Argentina")
    else
        println("${persona1.nombre} no es mayor si vive en Argentina")
    if (persona1.esMayor(::mayorEstadosUnidos))
        println("${persona1.nombre} es mayor si vive en Estados Unidos")
    else
        println("${persona1.nombre} no es mayor si vive en Estados Unidos")
}

Declaramos la clase Persona con dos propiedades llamadas nombre y edad:

class Persona(val nombre: String, val edad: Int) {

La clase persona por si misma no guarda la nacionalidad de la persona, en cambio cuando se pregunta si es mayor de edad se le pasa como referencia una función que al pasar la edad nos retorna true o false:

fun esMayor(fn:(Int) -> Boolean): Boolean {
        return fn(edad)
    }

Tenemos dos funciones que al pasar una edad nos retornan si es mayor de edad o no:

fun mayorEstadosUnidos(edad: Int): Boolean {
    if (edad >= 21)
        return true
    else
        return false
}

fun mayorArgentina(edad: Int): Boolean {
    if (edad >= 18)
        return true
    else
        return false
}

En la función main creamos un objeto de la clase persona:

val persona1 = Persona("juan", 18)

Llamamos al método esMayor del objeto persona1 y le pasamos la referencia de la función “mayorArgentina”:

 if (persona1.esMayor(::mayorArgentina))
        println("${persona1.nombre} es mayor si vive en Argentina")
    else
        println("${persona1.nombre} no es mayor si vive en Argentina")

Ahora llamamos al método esMayor pero pasando la referencia de la función “mayorEstadosUnidos”:

if (persona1.esMayor(::mayorEstadosUnidos))
        println("${persona1.nombre} es mayor si vive en Estados Unidos")
    else
        println("${persona1.nombre} no es mayor si vive en Estados Unidos")

Como podemos comprobar el concepto de funciones de orden superior es aplicable a los métodos de una clase.

No hicimos un código más conciso con el objeto que quede más claro la sintaxis de funciones de orden superior, pero el mismo problema puede ser:

class Persona(val nombre: String, val edad: Int) {
    fun esMayor(fn:(Int) -> Boolean) = fn(edad)
}


fun mayorEstadosUnidos(edad: Int) = if (edad >= 21) true else false

fun mayorArgentina(edad: Int) = if (edad >= 18) true else false

fun main(parametro: Array<String>) {
    val persona1 = Persona("juan", 18)
    if (persona1.esMayor(::mayorArgentina))
        println("${persona1.nombre} es mayor si vive en Argentina")
    else
        println("${persona1.nombre} no es mayor si vive en Argentina")
    if (persona1.esMayor(::mayorEstadosUnidos))
        println("${persona1.nombre} es mayor si vive en Estados Unidos")
    else
        println("${persona1.nombre} no es mayor si vive en Estados Unidos")
}

Fuente: https://www.tutorialesprogramacionya.com/kotlinya/detalleconcepto.php?punto=36&codigo=36&inicio=30



Básicamente entendí que las funciones lambda son funciones que se pueden enviar como parámetro a otras funciones. Esto por que los parámetros de una función pueden variar en función de un dato.

fun main() {
//High-Order Function
    val resultHighOrder = addTwoNum(myLambdaFunc(2,2),myLambdaFunc(2,2))
    print(resultHighOrder) // result = 8
}
//{x, y-> x + y} Lambda: A function without name
fun addTwoNum(x: Int, y: Int):Int{ //Parameters
    return x + y //Method Body
}
//Lambda Expression
val myLambdaFunc: (Int, Int)-> Int = {x, y-> x + y}

pues esto es un callback ¿no?

En esta clase si que quedé boludo!

Código de la clase


fun main(args: Array<String>){
    var largoValorInit = superFunction(valorInit = "Hola", block = {
        it.length
    })
    println(largoValorInit)

    val lambda = functionInception("David")
    println(lambda())
}

fun superFunction (valorInit: String, block : (String)->Int) :Int {
    return block(valorInit)
}

fun functionInception (nombre:String): () -> String {
    return{
        "Hola"+" "+nombre
    }
}

La variable lambda se convierte en una Lambda heredando el tipo de input y return de funtionInception()

fun main() {
    val lambda : () -> String = funtionInception("Chair")
    println(lambda())
    // Consola = Objet from Lambda: Chair
}

fun funtionInception(name : String) : () -> String {
    return {"Objet from Lambda: $name"}
}
fun main() {
    val lambda = funtionInception(7)
    println(lambda(2))  //Consola = 3.5
}

fun funtionInception(number : Int) : (Int) -> Double {
    return {divider -> number.toDouble()/divider.toDouble()}
}

dejo mi aporte, me sirvio para practicar y entender la dinamica de la HOF:
Es una funcion que retorna una funcion. Recibe de parametro un nombre, lo busca en el map e imprime su valor. Si no esta el nombre ingresado, como el de Lisa, imprime un mensaje acorde.

Prestem atemcopm al return de la funcion generarFraseSimpsons, lo que devuelve esta entre llaves porque debe ser una lambda. Ii sacamos esas llaves, lo que devuelve seria un String, y no seria lo que necesitamos.

fun main(args: Array<String>) {
    // High Order function == retorna una funcion
    val fraseHomero: () -> String = generarFraseSimpsons("homero")
    // opcion 1
    println(fraseHomero) // Function0<java.lang.String>
    println(fraseHomero())
    // opcion 2
    val valorFraseHomero: String = fraseHomero()
    println(valorFraseHomero)

    val fraseJimbo = generarFraseSimpsons("jimbo")
    println(fraseJimbo())

    val fraseLisa = generarFraseSimpsons("lisa")
    println(fraseLisa())
}

val mapaFrases = mutableMapOf(
    "homero" to "a la grande le puse cuca...",
    "bart" to "comete mis calzones",
    "jimbo" to "chupame el pie skinner",
    "skinner" to "no no no! dije hamburguejas, hamburguejas al vapor!"
)

fun generarFraseSimpsons(nombre: String): () -> String {
    return {
        if (mapaFrases.contains(nombre)) {
            "Frase de $nombre : ${mapaFrases[nombre]} "
        } else {
            "No tenemos frase para $nombre"
        }
    }
} 



output:
Function0<java.lang.String>
Frase de homero : a la grande le puse cuca... 
Frase de homero : a la grande le puse cuca... 
Frase de jimbo : chupame el pie skinner 
No tenemos frase para lisa

Genial estos cursos!

Función de orden superior –

  • En Kotlin, una función que puede aceptar una función como parámetro o puede devolver una función se llama función de orden superior . En lugar de Integer, String o Array como parámetro para funcionar, pasaremos una función anónima o lambdas. Con frecuencia, las lambdas se pasan como parámetro en las funciones de Kotlin por conveniencia.

-Pasar la expresión lambda como parámetro a la función de orden superior:
Podemos pasar una expresión lambda como parámetro a la función de orden superior.
Hay dos tipos de expresiones lambda que se pueden pasar:

  • Expresión lambda que devuelve Unidad
  • Expresión lambda que devuelve cualquiera de los valores enteros, cadenas, etc.
 // lambda expression
var lambda = {println("GeeksforGeeks: A Computer Science portal for Geeks") }
      // higher-order function
fun higherfunc( lmbd: () -> Unit ) {     // accepting lambda as parameter
    lmbd()                               //invokes lambda expression
}
fun main(args: Array<String>) {
     //invoke higher-order function
    higherfunc(lambda)                 // passing lambda as parameter

Explicación:
comprendamos el programa anterior paso a paso:
en la parte superior, definimos una expresión lambda que contiene print() para imprimir una cadena en la salida estándar.


var lambda = {println("GeeksforGeeks: un portal de informática para geeks") }

luego, definimos una función de orden superior que contiene un parámetro.

lmbd: () -> Unidad

lmbd es el nombre local del parámetro lambda de recepción.
() representa que la función no acepta ningún argumento.
La unidad representa que la función no devuelve ningún valor.
En la función principal, hemos invocado la función de orden superior pasando la expresión lambda como parámetro.

función superior (lambda)

Me gustaría que escribiesen la redacción de este curso, o se dice todo en inglés, o se dice todo en español.
El “Espanglish” como lo conocemos en México es pésimo cuando le enseñas a alguien un concepto literal.

Un ejemplo de una función de orden superior, que toma una función como parámetro

/*--------------TOMANDO FUNCIONES COMO PARÁMETROS-----------------*/

//Declarando un función de orden superior. Toma dos parámetros, x e y.
//Adicionalmente toma otra función como parámetro.
//Los parámetros de operación y el tipo de retorno también se definen en la declaración
fun calculate(x: Int, y: Int, operation: (Int, Int) -> Int): Int {
    //La función de orden superior devuelve el resultado de la invocación de la operación con los argumentos proporcionados
    return operation(x, y)
}

//Declara una función que coincide con la firma de la operación
fun sum(x: Int, y: Int) = x + y

fun main() {
    //Invoca la función de orden superior pasando dos valores enteros y el argumento de la función ::suma
    //:: es la notación que hace referencia a una función por su nombre en Kotlin.
    val sumResult = calculate(4, 5, ::sum)

    //Invoca la función de orden superior pasando un lambda como argumento de función.
    val mulResult = calculate(4, 5) { a, b -> a * b }
    println("sumResult $sumResult, mulResult $mulResult")

Block es una sintaxis recomendada por kotlin para nombrar las lambdas, puedes nombrar block cuando vas a ejecutar un codigo o la puedes llamar event o listener cuando vas a realizar una acción dependiendo de un evento

ese tipo solo le importa que algunos entienda

Las funciones de orden superior son funciones que reciben como parametro a otras funciones, esto es un “template” o la forma mas generica de definir una funcion de orden superior.

Mas info aqui

fun main(args: Array<String>){
    var largoValorInit = superFunction(valorInit = "Hola", block = {
        it.length
    })
    println(largoValorInit)

    val lambda = functionInception("David")
    println(lambda())
}

fun superFunction (valorInit: String, block : (String)->Int) :Int {
    return block(valorInit)
}

fun functionInception (nombre:String): () -> String {
    return{
        "Hola"+" "+nombre
    }
}