Котлин составляет список функций

В настоящее время я использую compose из библиотеки с именем arrow, которая определила его таким образом.

inline infix fun <IP, R, P1> ((IP) -> R).compose(crossinline f: (P1) -> IP): (P1) -> R = { p1: P1 -> this(f(p1)) }

То, что я пытаюсь сделать, это составить функции из списка, поэтому я предположил что-то настолько простое, как это будет работать.

val add5 = { i: Int -> Option(i + 5) }
val multiplyBy2 = { i: Int -> i * 2 }
fun isOdd(x: Option<Int>) = x.map { y -> y % 2 != 0 }

val composed = listOf(::isOdd, add5, multiplyBy2).reduce { a, b -> a compose b  }

но я получаю ошибку типа:

Ошибка вывода типа: Невозможно определить тип параметра IP в потоке инфиксного ввода ((IP) -> R).compose(межстрочный интервал f: (P1) -> IP): (P1) -> R Ни один из следующих получателей замен: (Любой) -> Любые аргументы: ((Nothing) -> Any) получатель: (Nothing) -> Любые аргументы: ((Nothing) -> Nothing) могут быть применены к получателю: Function1<, Any> arguments: (Function1<, Any >)

поэтому я стараюсь:

val composed = listOf<(Any) -> Any>(::isOdd, add5, multiplyBy2).reduce { x, y -> x compose y }

и я получаю это:

Несоответствие типов: предполагаемый тип - KFunction1<@ParameterName Option, Option>, но (Any) -> Any ожидаемый

Несоответствие типов: предполагаемый тип (Int) -> Option, но (Any) -> Any ожидается

Несоответствие типов: предполагаемый тип (Int) -> Int, но (Any) -> Ожидается любой

Любая помощь приветствуется. Я не против, если мне придется написать свою собственную версию сочинения. Мне просто нужно составить список функций.

редактировать:

Это работает без проблем:

val composed = ::isOdd compose add5 compose multiplyBy2

Я просто пытаюсь достичь того же результата, если у меня есть список функций вместо того, чтобы писать таким образом.

1 ответ

Мне трудно представить, как простое compose должно работать с методами с такими разными сигнатурами. Итак, сначала мы должны выровнять типы функций. Arrow позволяет вам составлять функции, если возвращаемый тип первого совпадает с параметром второго...

Другая проблема заключается в том, что isOdd это Predicate, Это не трансформирует ценность.

Если у трансформаторов есть совместимая подпись, вы можете составить их, например: andThen

Вот версия, которая выравнивает типы для составления функций. Обратите внимание, что filter а также map специальные функции в стрелках Option которые позволяют передавать функции / предикаты преобразователя

import arrow.core.Option
import arrow.core.andThen
import org.hamcrest.Matchers.`is`
import org.junit.Assert.assertThat
import org.junit.Test

class ComposeTest {

    @Test
    fun shouldCompose() {
        val add5 = { i: Int -> i + 5 }
        val multiplyBy2 = { i: Int -> i * 2 }
        val isOdd = { x: Int -> x % 2 != 0 }

        val composed: (Int) -> Option<Int> = { i: Int -> Option.just(i)
          .filter(isOdd)
          .map(add5.andThen(multiplyBy2))
        }

        assertThat(composed(3), `is`(Option.just(16)))
        assertThat(composed(4), `is`(Option.empty()))
    }
}
Другие вопросы по тегам