【问题标题】:Kotlin Higher Order Function CompositionKotlin 高阶函数组合
【发布时间】:2018-02-22 16:29:49
【问题描述】:

我试图弄清楚如何在 Kotlin 中将一个函数声明性地定义为其他两个函数的组合,但我正在苦苦挣扎。这是我的代码:

fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): Int {
    return a.invoke() + b.invoke()
}

compose 函数的想法是,它将接受两个函数作为输入(这两个函数都接受两个 Int 并返回一个 Int)并返回两个传递函数的结果之和。问题是我必须调用传递的函数来计算它们的总和(显然是大声笑),但我不知道我希望在 compose 方法中调用的值(它们是传递给函数的值)。

我在这里完全错过了什么吗?我知道这在 Haskell 这样的语言中是可能的,在 Kotlin 中是否可能?

【问题讨论】:

  • 组合ab 通常意味着将a 应用于b 应用于某个参数的结果,但这并不是你真正想要的。
  • 是的。名称compose 表示一些特定的操作:函数f(x)g(x)的组合是g(f(x)),而不是函数和。

标签: kotlin higher-order-functions kotlin-higher-order-functions


【解决方案1】:

一种方式:

您必须像这样将两个 Int 作为附加参数传递给 compose

fun compose(
    c: Int, d: Int, a: (Int, Int) -> Int, b: (Int, Int) -> Int
) = a(c, d) + b(c, d)

Lambda 是更深层次的抽象,它使您有机会使行为可变,您仍然必须为它们提供数据。

更抽象的方法:

您可以进一步抽象,让 compose 返回一个 lambda,它结合了其他两个 lambda 的结果(我们称之为 compose2):

// return type is inferred to (Int, Int) -> Int
fun compose2(a: (Int, Int) -> Int, b: (Int, Int) -> Int) = { 
     c: Int, d: Int -> a(c, d) + b(c, d)
}

val f = compose2(/* pass lambdas */)

f 本身就是一个 lambda,可以这样调用:

f(2, 4)

所以,compose2 只是返回一个 lambda,它将两个传递的 lambda 的结果相加。实际调用是在 compose2 之外完成的。

更抽象的方法:

在您的 compose 函数中,您使用简单的加法作为合成操作。您甚至可以通过传递第三个 lambda ab 来使此操作变量,它告诉您的函数如何组合 ab

fun compose3(
    a: (Int, Int) -> Int, b: (Int, Int) -> Int, ab: (Int, Int) -> Int
) = { 
    c: Int, d: Int -> ab(a(c, d), b(c, d))
}

结果还是一个 lambda,它接受两个 Int 并返回一个 Int。

【讨论】:

    【解决方案2】:

    您需要一个新函数(Int, Int) -> Int,它是两个(Int, Int) -> Int 函数的总和。

    因此,compose(...) 返回的是另一个 (Int, Int) -> Int 类型函数。

    现在,我们有了函数compose 的类型。它返回一个函数,而不是 Int 值。

    fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int
    

    它的身体呢?

    它将返回一个函数。让我们返回一个 lambda 表达式 { x: Int, y: Int -> a(x, y) + b(x, y) }

    fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int {
        return { x: Int, y: Int -> a(x, y) + b(x, y)}
    }
    

    现在我们可以省略所有不必要的部分。

    fun compose(a: (Int, Int) -> Int, b: (Int, Int) -> Int): (Int, Int) -> Int =
        { x, y -> a(x, y) + b(x, y) }
    

    就是这样。

    【讨论】:

      【解决方案3】:

      另一个有价值的方法是使用中缀扩展功能。对于您的参数类型为Int 的情况,它可以是这样的:

      // Extension function on lambda
      private infix fun ((Int, Int) -> Int).plus(f: (Int, Int) -> Int) = {
          p1: Int, p2: Int, p3: Int, p4: Int -> this(p1, p2) + f(p3, p4)
      }
      
      // Usage
      val first: (Int, Int) -> Int = { a, b -> a + b }
      val second: (Int, Int) -> Int = { a, b -> a - b }
      
      // first two parameters (1 and 2) for the `first` lambda, 
      // second two parameters (4 and 3) for the `second` lambda
      val sum = (first plus second)(1, 2, 4, 3) // result is 4
      

      【讨论】:

      • ...或者如果你把infix改成operator你可以写first + second
      猜你喜欢
      • 2021-05-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-04-04
      • 2018-05-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多