gedachtenkaart

training_kotlin

Functionele programmering

De oefeningen zijn uit het boek:
Functioneel programmeren in Kotlin via tutorials
Geschreven door Massimo Carli
repo: https://github.com/kodecocodes/fpk-materials

Syntaxis

EersteProgrammaTest

notions: weergave scherm, functie
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[bron]+

ConcatFunctionTest

begrippen: geheugen, variabele, waarde, object, functie-uitbreiding
(empty)bron+

VerjaardagsberichtTestUitvoer

noties: verzamelingen, lussen
Inleiding tot Kotlin
BirthdayMessageTestOutput:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[bron]+

Cursus kotlin

Zelfstudie over collecties in Java

Het hart van de collectie-interfaces
Collecties

functionele basis

Declaratief X imperatieve aanpak

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

Oefening 1.1

Implementeer de functie sumInRange, die de waarden in optelt
een List<String> binnen een gegeven interval. De handtekening is :

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

Probeer het en controleer je antwoord met dehttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[oplossing, windows="_blank].

Functies van hogere orde

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

Oefening 1.2

Implementeren chrono, die een functie van type accepteert`() →`
Eenheid neemt invoer aan en retourneert de tijd die nodig is om het uit te voeren. De signatuur is:

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

Probeer het en controleer je antwoord met dehttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[oplossing, windows="_blank].

Compositie

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

}

Zuivere functies en testbaarheid

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

uitsonderingsafhandeling

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

Belangrijkste punten

  • Terwijl objectgeoriënteerde programmering betekent programmeren met objecten,

functionele programmering betekent programmeren met functies Je splitst een probleem op in verschillende deelproblemen, die je modelleert met de functies.

  • Functies van hogere orde accepteren andere functies als invoer of geven andere

werken als retourwaarden De categorietheorie is de theorie van de samenstelling, en je gebruikt het om te begrijpen Hoe u uw functies kunt samenstellen in een werkprogramma. De uitvoerwaarde van een zuivere functie hangt alleen af van zijn invoerparameters, en zij Heeft geen bijwerkingen.

  • Een bijwerking is iets wat een functie doet in de buitenwereld. Dit

kan een logboek zijn in de standaarduitvoer of het wijzigen van de waarde van een globale variabele. Functioneel programmeren werkt voor de zuivere functies, maar het biedt ook de gereedschappen om onzuivere functies te transformeren naar zuivere functies U kunt een onzuivere functie zuiver maken door de effecten te verplaatsen om ze deel van de retourwaarde.

  • Functioneel programmeren is een kwestie van compositie.

Foutafhandeling is een typisch voorbeeld van neveneffecten, en Kotlin geeft je de tools om ze functioneel te beheren.

Verdiepen Java8: lambda-expressies en functionele interfaces

Categorietheorie

De wiskundige theorie van de categorieën:

Grondslagen van functies

Oefening 2.1

Kun je een voorbeeld schrijven van een functie die verschillende waarden afbeeldt?
waarvan het domein van niet-onderscheidende waarden binnen het bereik, zoals f(b) en f(c) in de onderstaande figuur?

Probeer het, bekijk dan het uitdaging project voor een oplossing om te zien hoe je het hebt gedaan.
U vindt advies en een uitleg door de link te volgen naar de oplossing.

Oefening 2.2

Kun je de inverse functie van verdubbelen schrijven?
Wat zijn het domein en het bereik voor de inverse functie?
Bekijk het uitdagingproject en Bijlage B voor de oplossing.

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

Probeer het en controleer je antwoord met dehttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[oplossing, windows="_blank].

Gerelateerde artikelen