Котлин составляет список функций
В настоящее время я использую 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()))
}
}