Kotlin funkcyjnie - jak czytać kompozycję funkcji

0

Cześć,

chciałem poczytać trochę podstaw o programowaniu funkcyjnym w Kotlinie i trafiłem na taki artykuł: https://www.raywenderlich.com/9527-functional-programming-with-kotlin-and-arrow-getting-started
doszedłem do takiej funkcji

infix fun <A, B, C> Func<B, C>.after(f: Func<A, B>): Func<A, C> = { x: A -> this(f(x)) }

i nijak nie mogę zrozumieć jak ją czytać i jak ona w ogóle działa. Przedstawię cały kod:

typealias Func<A, B> = (A) -> B

val getPrice: Func<Book, Price> = { book -> book.price }
val formatPrice: Func<Price, String> = fun(priceData: Price) = "value: ${priceData.value}${priceData.currency}"

//zawile dziadostwo
infix fun <A, B, C> Func<B, C>.after(f: Func<A, B>): Func<A, C> = { x: A -> this(f(x)) }

fun main() {
    val compositeResult: String = (formatPrice after getPrice)(books[0])
    println(compositeResult)
}

data class Price(val value: Double, val currency: String = "$")

data class Book(
  val ISDN: String,
  val name: String,
  val pages: Int,
  val price: Price,
  val weight: Double,
  val year: Int,
  val author: String
)
val books = listOf<Book>(
  Book(
    "8850333404",
    "Android 6: guida per lo sviluppatore (Italian Edition)",
    846,
    Price(39.26, "£"),
    2.1,
    2016,
    "Massimo Carli"
  ))

Wywołanie tego kodu daje wynik: value: 39.26£

No dobra to teraz jak czytać tę funkcje .after?
Rozumiem, że .after dostaje jako argument getPrice, czyli A (Book) jest zamieniane na B (Price) podczas wywołanie f(x). this odnosi się do formatPrice, który zamienia B (Price) otrzymany z getPrice wcześniej na C (String). Tylko dlaczego ta funkcja zwraca Func<A, C>? Po to żeby dało się ciało tej lambdy zapisać?

Jeśli uda się to komuś jaśniej to opisać byłbym bardzo wdzięczny ;)

0

A co innego chciałbyś zwrócić? Samo C? Musiałbyś wtedy z góry wiedzieć jaki jest argument wejściowy A.

6

after to jest zwykłe złożenie funkcji g ∘ f czyli jak masz g(x) = ... i f(x) = .... to g.after(f) (x) = g(f(x))

Kod jest IMO zaciemniony przez ten typealias typealias Func<A, B> = (A) -> B - javaizm
Dla mnie taki zapis jest bardziej oczywisty:
infix fun <A, B, C> ((B)->C).after(f: (A)->B): (A)->C = { x: A -> this(f(x)) }

Biore funkcję z A->B składam (after) z funckcją B->C i mam w wyniku funkcję A->C.

symbol kompozycji czyta się jako after

Ogólnie, żeby było najczytelniej zapisałbym to w dwóch krokach

fun <A, B, C> compose(f : (A)->B, g : (B)->C) = {x:A -> g(f(x))}

infix fun <A, B, C> ((B)->C).after(f: (A)->B): (A)->C = compose(f, this)
0

Ok, dzięki @jarekr000000 za wytłumaczenie. Zapis tej funkcji był dla mnie nieczytelny, ale to może kwestia przyzwyczajenia albo przez moją słabą znajomość kotlina i lambd.

Próbowałem jeszcze napisać taki after dla lambd z dwoma argumentami, czyli (A,B) -> C i mi nie szło, ale stwierdziłem że łatwiej to zastąpić (Pair<A, B>) -> C i wykorzystać after napisany powyżej.

1 użytkowników online, w tym zalogowanych: 0, gości: 1