Entrenamiento - Kotlin
Publié le 12 May 2022
Programación en kotlin, plan.
Mapa mental

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
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].
