Kotlin支持部分应用吗?

问题描述 投票:0回答:3

由于 Kotlin 支持函数式编程的许多概念,我想知道是否也有一种方法可以在 Kotlin 中部分应用函数?

部分应用有用的一个例子是:

// In one class
fun doSomething(cb: (a, b) -> Unit) {
    <some logic here to compute someField>
    doSomethingElse(cb.applyPartially(someField))
}

// In another class
fun doSomethingElse(cb: (b) -> Unit) {
    <some logic here to compute someOtherField>
    cb(someOtherField)
}
kotlin functional-programming partial-application
3个回答
22
投票

开箱即用,不。但使用辅助函数并不难:

    fun add(a: Int, b:Int): Int {
        return a + b
    }

    fun <A, B, C> partial2(f: (A, B) -> C, a: A): (B) -> C {
        return { b: B -> f(a, b)}
    }

    val add1 = partial2(::add, 1)

    val result = add1(2) //3

因此,partial2 接受一个有 2 个参数的函数和第一个参数,并应用它来获得一个有 1 个参数的函数。您必须为您需要的所有类型编写这样的帮助程序。

或者,您可以使用扩展方法来完成:

fun <A,B,C> Function2<A,B,C>.partial(a: A): (B) -> C {
    return {b -> invoke(a, b)}
}

val abc: (Int) -> Int = (::add).partial(1)

6
投票

2024 年更新:

org.funktionale
已被弃用,功能已迁移到
arrow-kt.io

https://arrow-kt.io/learn/collections-functions/utils/


原答案:

Kotlin 有一个非常漂亮且轻便的库:

org.funktionale
。在模块
funktionale-currying
中,您将找到 lambda 的扩展方法:
curried()
uncurried()

示例:

val add = { x: Int, y: Int -> x + y }.curried()
val add3 = add(3)

fun test() {
    println(add3(5)) // prints 8
}

2
投票

选项1

确实如此,但你必须使用类似的签名

(T1) -> (T2) -> R

这是一个允许部分应用的柯里化比较器的示例(为了可读性而添加的

typealias
,也可以重写,不带任何内容):

typealias CurriedComparator<T> = (T) -> (T) -> Int

fun main() {
    val integers = mutableListOf(42, 0, 1, 3, 2)

    val naturalOrder: CurriedComparator<Int> = { left ->
        { right ->
            // JVM only, essentially the same as `left - right`
            Comparator.naturalOrder<Int>().compare(left, right)
        }
    }

    integers.sortWith { left, right ->
        // Note the partial application:
        naturalOrder(left)(right)
    }

    println(integers)
}

如上所述,双参数函数的

curried
操作(来自这个答案)可以这样实现:

val <T1, T2, R> ((T1, T2) -> R).curried: (T1) -> (T2) -> R
    get() = { arg0: T1 ->
        { arg1: T2 ->
            this(arg0, arg1)
        }
    }

使用示例:

val difference = { a: Int, b: Int -> a - b }.curried(11)(7)
println(difference) // 4

选项2

您必须重载

invoke()
运算符,例如。克:

    val compareInts: (Int, Int) -> Int =
        { left, right ->
            left - right
        }

    operator fun <T1, T2, R> ((T1, T2) -> R).invoke(t1: T1): (T2) -> R =
        { t2 ->
            this(t1, t2)
        }

    // This is the "normal" invocation:
    val a: Int = compareInts(41, 42)
    // This is the partial application using the overloaded `invoke()` operator:
    val b: Int = compareInts(41)(42)

    check(a == b)

限制

部分应用的能力是有代价的。一旦我们遵循上述路径,我们将立即失去对:

的访问权限
  • Java 互操作性,
  • 默认参数,更重要的是,
  • 递归(仍然可以使用Y组合器来实现)。

说到没有Y组合器递归,它仍然是可能的,但是(在2参数函数的情况下)你必须重写

val comparator: (String) -> (String) -> Int = { /*...*/ }

fun comparator(left: String): (String) -> Int { /*...*/ }
© www.soinside.com 2019 - 2024. All rights reserved.