Kotlin高阶函数组合

5

我正在尝试找出如何在Kotlin中以声明方式定义一个由两个其他函数组成的函数,但我很困惑。以下是我的代码:

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

compose函数的概念是它将两个函数作为输入(这两个函数都需要两个整数作为参数,并返回一个整数),并返回两个传递函数的结果之和。问题在于,我必须调用传递的函数以计算它们的总和,但我不知道我希望在compose方法中调用哪些值(它们是传递给函数的值)。
我完全错过了什么吗?我知道在像Haskell这样的语言中可以做到,但在Kotlin中是否可能呢?

2
组合 ab 通常意味着将 a 应用于对某个参数应用 b 的结果,但这并不是您实际想要的。 - Marko Topolnik
2
是的。compose 这个名称表示一些特定的操作:函数 f(x)g(x) 的组合g(f(x)),而不是函数求和。 - Naetmul
3个回答

4

方法一:

您需要将这两个整数作为附加参数传递给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))
}

结果是,再次得到一个接受两个Int并返回一个Int的lambda表达式。

4
您需要一个新的函数 (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) }

这就是全部内容。


1

另一个值得尝试的方法是使用中缀扩展函数。对于参数类型为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

1
...或者如果你把 infix 改成 operator,你就可以写成 first + second - charles-allen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接