Mindmap

Bild:../../diagram/training_kotlin.png[training_kotlin]

Funktionale Programmierung

Die Übungen werden aus dem Buch entnommen:
Funktionale Programmierung in Kotlin anhand von Tutorials
Geschrieben von Massimo Carli
Repository: https://github.com/kodecocodes/fpk-materials

Syntax

FirstProgramTest

notions: Bildschirmanzeige, Funktion
FirstProgramTest:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/FirstProgramTest.kt[Quelle]+

ConcatFunctionTest

Konzepte: Speicher, Variable, Wert, Objekt, Funktionserweiterung
ExampleUnitTest: Quelle+

BirthdayMessageTestOutput

Begriffe: Mengen, Schleifen
Einführung in Kotlin
BirthdayMessageTestOutput:https://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/programming/BirthdayMessageTestOutput.kt[Quelle]

Kotlin-Kurs

Tutorial zu den Collections in Java

Das Herz der Sammlungsschnittstellen
Collections

Funktionelle Grundlagen

deklarative X imperativer Ansatz

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

Übung 1.1

Implementiere die Funktion sumInRange, die die Werte in
Eine List<String> in einem gegebenen Intervall. Die Signatur ist :

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

Versuchen Sie es und überprüfen Sie Ihre Antwort mit demhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/DeclarativeTests.kt[Lösung, windows="_blank].

Funktionen höherer Ordnung

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

Übung 1.2

Implementiere chrono, das eine Funktion vom Typ`() →`
Die Einheit wird als Eingabe übergeben und gibt die für die Ausführung benötigte Zeit zurück. Die Signatur lautet:

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

Versuchen Sie es und überprüfen Sie Ihre Antwort mit derhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[Lösung, windows="_blank].

Komposition

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

}

Reine Funktionen und Testbarkeit

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

Ausnahmebehandlung

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

Schlüsselpunkte

  • Während die objektorientierte Programmierung bedeutet, mit Objekten zu programmieren,

Funktionale Programmierung bedeutet, mit Funktionen zu programmieren. Du zerlegst ein Problem in mehrere Teilprobleme, die du mit die Funktionen.

  • Funktionen höherer Ordnung akzeptieren andere Funktionen als Eingabe oder geben andere

funktionieren wie Rückgabewerte. Die Kategorientheorie ist die Theorie der Komposition, und Sie verwenden sie, um zu verstehen Wie Sie Ihre Funktionen in einem Arbeitsprogramm komponieren. Der Ausgabewert einer reinen Funktion hängt ausschließlich von ihren Eingabeparametern ab, und sie hat keine Nebenwirkungen.

  • Ein Nebeneffekt ist etwas, was eine Funktion an die Außenwelt ausführt. Dies

Es kann ein Journal in der Standardausgabe oder die Änderung des Werts einer globalen Variablen sein. Funktionale Programmierung funktioniert für reine Funktionen, aber sie stellt auch die Werkzeuge zum Umwandeln von unreinen Funktionen in reine Funktionen. Sie können eine unreine Funktion rein machen, indem Sie die Effekte verschieben, um sie Teil des Rückgabewerts

  • Funktionale Programmierung ist eine Frage der Komposition.

Die Fehlerbehandlung ist ein typischer Fall von Nebenwirkungen, und Kotlin gibt dir die Werkzeuge. um sie funktional zu verwalten.

Java8 vertiefen: Lambda-Ausdrücke und funktionale Schnittstellen

Kategorientheorie

Die mathematische Kategorientheorie:

Grundlagen der Funktionen

Übung 2.1

Können Sie ein Beispiel für eine Funktion schreiben, die verschiedene Werte abbildet
dessen Definitionsbereich nicht verschiedene Werte im Wertebereich annimmt, wie f(b) und f(c) in der untenstehenden Abbildung?

Probier es aus, dann schau dir das Challenge-Projekt nach einer Lösung an, um zu sehen, wie du es gemacht hast.
Sie werden Ratschläge und eine Erklärung finden, indem Sie dem Link zur Lösung.

Übung 2.2

Können Sie die Umkehrfunktion von zwei Mal schreiben?
Was sind Definitionsbereich und Wertebereich der inversen Funktion?
Schauen Sie sich das Challenge-Projekt und Anhang B für die Lösung an.

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

Probiere es aus und überprüfe deine Antwort mit derhttps://github.com/cheroliv/cheroliv.com/blob/master/codes/src/test/kotlin/functional/BasicsHOFTests.kt[Lösung, windows="_blank].

Verwandte Artikel