mapa mental

training_kotlin

Programação funcional

Os exercícios são tirados do livro:
Programação funcional em Kotlin por tutoriais
Escrito por Massimo Carli
repositório: https://github.com/kodecocodes/fpk-materials

sintaxe

FirstProgramTest

noções: exibição de tela, função
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[source]+

ConcatFunctionTest

noções: memória, variável, valor, objeto, extensão de função
ExampleUnitTest: fonte+

BirthdayMessageTestOutput

noções: conjuntos, laços
Introdução ao Kotlin
BirthdayMessageTestOutput:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[fonte]

Curso de kotlin

Tutotiel sobre as coleções em Java

O coração das interfaces de coleção
coleções

Básicos funcionais

Abordagem declarativa X imperativa

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")
        })
    }
}

Exercício 1.1

Implementar a função sumInRange, que soma os valores em
uma List<String> dentro de um intervalo dado. A assinatura é:

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") }
    )
}

Experimente e verifique sua resposta com ahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[solution, windows="_blank].

Funções de ordem 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() }
}

Exercício 1.2

Implementar chrono, que aceita uma função do tipo`() →`
Unidade na entrada e devolve o tempo gasto para executá-lo. A assinatura é :

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

Experimente-o e verifique sua resposta com ahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[solução, windows="_blank].

Composição

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))
    }

}

Funções puras e testabilidade

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)
        }
    }
}

Tratamento de exceções

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
        )
    }
}

Pontos-chave

  • Enquanto a programação orientada a objetos significa programar com objetos,

programação funcional significa programar com funções. Você decompõe um problema em vários subproblemas, que você modela com as funções

  • As funções de ordem superior aceitam outras funções como entrada ou retornam outras

funcionam como valores de retorno. A teoria das categorias é a teoria da composição, e você a usa para entender como compor suas funções em um programa de trabalho. O valor de saída de uma função pura depende apenas dos seus parâmetros de entrada, e ela não tem efeitos colaterais

  • Um efeito colateral é algo que uma função faz no mundo exterior. Este

pode ser um log na saída padrão ou a modificação do valor de uma variável global. A programação funcional funciona para as funções puras, mas ela fornece também os ferramentas para transformar funções impuras em funções puras. Você pode tornar uma função impura pura movendo os efeitos para torná-los parte do valor de retorno.

  • Programação funcional é uma questão de composição.

Gerenciamento de erros é um caso típico de efeitos colaterais, e Kotlin lhe fornece as ferramentas para gerenciá-los de forma funcional

Aprofundar java8: lambdas expressões e interface funcionais

Teoria das categorias

A teoria matemática das categorias:

Fundamentos das funções

Exercício 2.1

Pode escrever um exemplo de função mapeando valores distintos?
cujo domínio assume valores não distintos no intervalo, como f(b) e f(c) na figura abaixo ?

Experimente, depois verifique o projeto do desafio para uma solução para ver como você fez.
Você encontrará conselhos e uma explicação seguindo o link para a solução.

Exercício 2.2

Você pode escrever a função inversa de duas vezes ?
Quais são o domínio e a imagem da função inversa?
Confira o projeto do desafio e o Apêndice B para a solução.

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

Experimente-o e verifique sua resposta com ahttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[solução, windows="_blank].

Articles connexes