Programación en kotlin, plan.

Mapa mental

training_kotlin

Programación funcional

Los ejercicios son tomados del libro:
Funcional programación en Kotlin por tutoriales
Escrito por Massimo Carli
repositorio: https://github.com/kodecocodes/fpk-materials

sintaxis

FirstProgramTest

nociones: pantalla de visualización, función
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[fuente]+

ConcatFunctionTest

conceptos: memoria, variable, valor, objeto, extensión de función
ExampleUnitTest: fuente+

BirthdayMessageTestOutput

noções: conjuntos, bucles
Introducción a Kotlin
BirthdayMessageTestOutput:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[source]+

Curso de kotlin

Tutorial sobre las colecciones en java

El corazón de las interfaces de colección
Colecciones

Básicos funcionales

declarativo X imperativo enfoque

package functional

import kotlin.test.Test
import kotlin.test.assertEquals

class DeclarativeTests {
    val input = listOf(
        "123", "abc", "1ds", "987", "abdf", "1d3", "de1", "88", "101"
    )

    fun imperativeSum(list: List<String>): Int {
        var sum = 0
        for (item in list) {
            try {
                sum += item.toInt()
            } catch (_: NumberFormatException) {
            }
        }
        return sum
    }

    @Test
    fun `test imperative approach`() {
        imperativeSum(input).run {
            println("Sum $this")
            assertEquals(1299, this)
        }
    }

    fun isValidNumber(s: String) = try {
        s.toInt()
        true
    } catch (_: NumberFormatException) {
        false
    }

    fun declarativeSum(list: List<String>) = list
        .filter(::isValidNumber)
        .map(String::toInt)
        .sum()

    @Test
    fun `test declarative approach`() {
        assertEquals(1299, declarativeSum(input).apply {
            println("Sum $this")
        })
    }
}

Ejercicio 1.1

Implementar la función sumInRange, que suma los valores en
una List<String> dentro de un intervalo dado. La firma es:

fun sumInRange(input: List<String>, range: IntRange): Int
@Test
fun `Exercise 1_1`() {
    assertEquals(4, sumInRange(
        listOf("1", "10", "a", "7", "ad2", "3"),
            1..5
        ).apply { println("sumInRange 1..5: $this") }
    )
}

Pruebalo y verifica tu respuesta con lahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[solución, windows="_blank].

Funciones de orden superior

package functional

import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.*
import java.lang.Thread.sleep
import kotlin.math.sign
import kotlin.test.Test
import kotlin.test.assertEquals

class BasicsHOFTests {
    val ONE_SECOND = 1000L

    @Test
    fun `high order function`() {
        //capture de la sortie standard
        val standardOut: PrintStream? = out
        val outputStreamCaptor = ByteArrayOutputStream()
        setOut(PrintStream(outputStreamCaptor))

        3.times { println("Hello") }
        assertEquals(
            buildString {
                repeat(3) { append("Hello\n") }
                deleteAt(length - 1)
            }, outputStreamCaptor
                .toString()
                .trim()
        )

        //libération de la sortie standard
        setOut(standardOut)
    }

    fun Int.times1(fn: () -> Unit) {
        for (i in 1..this) {
            fn()
        }
    }

    fun Int.times2(fn: () -> Unit) {
        for (i in 1..this) fn()
    }

    fun Int.times3(fn: () -> Unit) =
        (1..this).forEach { fn() }


    fun Int.times4(fn: () -> Unit) =
        repeat((1..this).count()) { fn() }

    fun Int.times(fn: () -> Unit) =
        (1..this).forEach { _ -> fn() }
}

Ejercicio 1.2

Implementar chrono, que acepta una función de tipo`() →`
Unidad de entrada y devuelve el tiempo transcurrido al ejecutarla. La firma es :

fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
    val waitOneSec = { sleep(ONE_SECOND) }
    chrono(waitOneSec).apply {
        println("chrono: $this")
        assertEquals(1, sign)
    }
}

Pruebe y verifique su respuesta con lahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[solución, windows="_blank].

Composición

package functional

import kotlin.test.Test
import kotlin.test.assertEquals


fun double(x: Int): Int = 2 * x
fun square(x: Int): Int = x * x
fun squareAndDouble1(x: Int) = double(square(x))

infix fun <A, B, C> ((A) -> B).compose(g: (B) -> C)
        : (A) -> C = { a -> g(this(a)) }

class CompositionTests {
    @Test
    fun composition_impure() {
        assertEquals(200, double(square(10)))
        assertEquals(200, squareAndDouble1(10))
    }

    @Test
    fun composition_pure() {
        val squareAndDouble = ::square compose ::double
        assertEquals(200, squareAndDouble(10))
    }

}

Funciones puras y testabilidad

package functional

import java.io.ByteArrayOutputStream
import java.io.PrintStream
import java.lang.System.out
import java.lang.System.setOut
import kotlin.test.Test
import kotlin.test.assertEquals


var count = 0

//impure car une variable global subit un effet de bord
fun impure(value: Int): Int {
    count++
    return value + count
}

//impure car utilisation de la sortie standard qui fait muter le system
fun addOneAndLog(x: Int): Int {
    val result = x + 1
    println("New Value is $result")
    return result
}

//pure
fun addOne(x: Int) = (x + 1).run {
    Pair(this, "New Value is $this")
}

class PureTests {
    @Test
    fun `impure fonction`() {
        assertEquals(3, impure(2))

        val standardOut = out
        val outputStreamCaptor = ByteArrayOutputStream()
        setOut(PrintStream(outputStreamCaptor))

        addOneAndLog(3)

        assertEquals(
            "New Value is 4",
            outputStreamCaptor
                .toString()
                .trim()
        )
        setOut(standardOut)
    }

    @Test
    fun `pure fonction`() {
        addOne(3).run {
            assertEquals(4, first)
            assertEquals("New Value is 4", second)
        }
    }
}

Manejo de excepciones

package functional

import org.junit.jupiter.api.assertThrows
import kotlin.Result.Companion.failure
import kotlin.Result.Companion.success
import kotlin.test.Test
import kotlin.test.assertEquals

//NumberFormatException est un effet de bord qui rend la fonction impure
fun strToInt(str: String) = str.toInt()

//pure
fun strToIntOrNull(str: String) = try {
    str.toInt()
} catch (nfe: NumberFormatException) {
    null
}

//pure avec gestion de l'exception plus élégante
fun strToIntResult(str: String): Result<Int> =
    try {
        success(str.toInt())
    } catch (nfe: NumberFormatException) {
        failure(nfe)
    }

class ExceptionHandlingTests {
    @Test
    fun impure() {
        assertThrows<NumberFormatException> { strToInt("foo") }
        assertEquals(1, strToInt("1"))
    }

    @Test
    fun pure() {
        assertEquals(null, strToIntOrNull("foo"))
        assertEquals(1, strToIntOrNull("1"))
    }

    @Test
    fun `pure avec result`() {
        assertEquals(1, strToIntResult("1").getOrNull())
        assertEquals(
            "For input string: \"foo\"",
            strToIntResult("foo")
                .exceptionOrNull()
                ?.message
        )
    }
}

Puntos clave

  • Mientras que la programación orientada a objetos significa programar con objetos,

la programación funcional significa programar con funciones. Usted descompone un problema en varios subproblemas, que modela con las funciones.

  • Las funciones de orden superior aceptan otras funciones como entrada o devuelven otras

funcionan como valores de retorno. La teoría de las categorías es la teoría de la composición, y la utiliza para comprender cómo componer tus funciones en un programa de trabajo. El valor de salida de una función pura depende únicamente de sus parámetros de entrada, y ella no tiene efectos secundarios.

  • Un efecto secundario es algo que una función hace al mundo exterior. Este

puede ser un registro en la salida estándar o la modificación del valor de una variable global. La programación funcional funciona para las funciones puras, pero también proporciona los herramientas para transformar funciones impuras en funciones puras. Puedes hacer que una función impura sea pura desplazando los efectos para hacerlos parte del valor de retorno

  • La programación funcional es una cuestión de composición.

La gestión de errores es un caso típico de efectos secundarios, y Kotlin te brinda las herramientas para gestionarlos de forma funcional

Profundizar java8: expresiones lambda y interfaces funcionales

Teoría de las categorías

La teoría matemática de las categorías:

Fundamentos de las funciones

Ejercicio 2.1

¿Puedes escribir un ejemplo de función que mapee valores distintos?
cuyo dominio toma valores no distintos en el intervalo, como f(b) y f(c) en la figura de abajo?

Pruébalo, luego verifica el proyecto del desafío para una solución y ver cómo lo hiciste.
Encontrará consejos y una explicación siguiendo el enlace hacia la solución.

Ejercicio 2.2

¿Puedes escribir la función inversa de dos veces?
¿Cuáles son el dominio y el rango de la función inversa?
Consulta el proyecto del desafío y el Apéndice B para la solución.

fun chrono(fn : () -> Unité) : Long
@Test
fun `Exercise 1_2`() {
    val waitOneSec = { sleep(ONE_SECOND) }
    chrono(waitOneSec).apply {
        println("chrono: $this")
        assertEquals(1, sign)
    }
}

Prueba-lo y verifica tu respuesta con lahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[solución, windows="_blank].

Articles connexes