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 鈥渙perar鈥:

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 鈥渇n鈥 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 鈥渇n鈥.

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 鈥渞esu1鈥.

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 鈥渕ayorArgentina鈥:

 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 鈥渕ayorEstadosUnidos鈥:

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 鈥淓spanglish鈥 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 鈥渢emplate鈥 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
    }
}