【问题标题】:Kotlin compose list of functionsKotlin 编写函数列表
【发布时间】:2018-08-24 05:54:44
【问题描述】:

目前我正在使用一个名为 arrow 的库中的 compose,它以这种方式定义。

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 fun ((IP) -> R).compose(crossinline f: (P1) -> IP): (P1) -> R 没有以下替换接收器:(任何)-> 任何参数:((无)-> 任何)接收器:(无)-> 任何参数: ((Nothing) -> Nothing) 可以应用于接收器:Function1 参数:(Function1)

所以我试试:

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

我明白了:

类型不匹配:推断类型是 KFunction1 但 (Any) -> Any 是预期的

类型不匹配:推断类型是 (Int) -> Option 但 (Any) -> Any 是预期的

类型不匹配:推断类型是 (Int) -> Int 但 (Any) -> Any 是预期的

任何帮助表示赞赏。我不介意我最终是否必须编写自己的 compose 版本。我只需要能够编写函数列表。

编辑:

这没问题:

val composed = ::isOdd compose add5 compose multiplyBy2

如果我有一个函数列表而不是这样写,我只是想达到相同的结果。

【问题讨论】:

    标签: kotlin functional-programming arrow-kt


    【解决方案1】:

    我很难想象一个简单的组合应该如何与具有如此不同签名的方法一起工作。所以首先我们必须对齐函数的类型。如果第一个的返回类型与第二个的参数匹配,箭头让我们编写函数...

    另一个问题是isOddPredicate。它不是在转换一个值。

    如果转换器具有兼容的签名,您可以使用例如andThen

    这是一个对齐类型以组成函数的版本。请注意,filtermap 是箭头 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()))
        }
    }
    

    【讨论】:

    • 换句话说,你认为不可能在kotlin中组成具有不同签名的函数列表吗?
    • 我无法想象这应该如何工作——至少不是没有关于如何将一种类型转换为另一种类型的逻辑。谓词根本不同——它们过滤而不是转换——所以它们需要以不同的方式组合(过滤器与映射)
    • 谓词正在从值转换为布尔值,对吧?
    • 你是对的——我的论点至少部分是错误的。我的观点是,在编写函数时签名需要兼容。对于andThen,第一个函数的输出需要是第二个函数的输入。但当然 compose 正在以相反的方式工作,因此 val composed = isOdd compose add5 compose multiplyBy2 确实有效。我的意图也错了——我以为@Bads 只想计算奇数值——但实际上,他想判断结果是否为奇数……
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-10
    • 1970-01-01
    • 2021-01-22
    • 1970-01-01
    • 1970-01-01
    • 2017-04-05
    • 1970-01-01
    相关资源
    最近更新 更多