Partial function application in Kotlin

Viewed 1442

I am having trouble with syntax for partial function application. The following code works fine, and it outputs: two-three-four

import kotlin.coroutines.experimental.*

inline fun <T> Iterable<T>.forEachFrom(beg:Int, act:(T)->Unit) {
  var i=0;  if (beg>=0) for (e in this) if (i++ >= beg) act(e)
}    // sample function I am testing; please don't change this!

fun main(a:Array<String>) {
  val l = listOf("zero", "one", "two", "three", "four")
  fun test() = buildSequence { l.forEachFrom(2) { yield(it) } }.joinToString("-")
  println(test())
}

I'd like to encapsulate my test(), so it is called as: test(l.forEachFrom(2)) However, I can't seem to get the types/syntax right. How would I re-write the test() function definition to make this possible?

1 Answers

It's not entirely clear what you're trying to achieve. If you give more details we can provide a better answer. That said, the following code will hopefully point you in the right direction.

import kotlin.coroutines.experimental.*

inline fun <T,S> Iterable<T>.mapFrom(beg:Int, act:(T)->S) =
    drop(beg).map {act(it)}

fun main(a:Array<String>) {
    val l = listOf("zero", "one", "two", "three", "four")
    fun <T> test(values: List<T>) = values.joinToString("-")
    println(test(l.mapFrom(2) {it}))
}

forEachFrom was not really being used as a forEach, but as a map. This was the main issue, as you were using yield to output the results instead of just returning the results. If forEachFrom was also going to be used for its side-effects, it can still be used for that purpose.

Also, there was no reason for test to take a function as a parameter instead of just accepting the output of that function as its parameter. The buildSequence call was also redundant as you immediately call joinToString which is terminal and forces eager computation of the function inside buildSequence.

Related