Приложение с частичной функциональностью в Kotlin

У меня проблемы с синтаксисом для приложения частичной функции. Следующий код работает нормально и выводит: 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())
}

Я хотел бы инкапсулировать свой test(), поэтому он называется: test(l.forEachFrom(2)) Однако я не могу правильно понять типы/синтаксис. Как мне переписать определение функции test(), чтобы это стало возможным?


person sirksel    schedule 08.11.2017    source источник
comment
Но ваш act возвращает Unit, как этот yield мог что-то собрать?   -  person madhead    schedule 08.11.2017
comment
Самая большая проблема в вашем случае, которая мешает мне прийти к простому решению, заключается в том, что сопрограммы Kotlin могут приостанавливать вызовы только из функций более высокого порядка, которые встроены, поэтому вы не можете просто сделать частично примененную функцию, написав лямбду, которая работает с последний аргумент и передать туда { yield(it) }: компилятору нужно место, где вы передаете его, как встроенную функцию.   -  person hotkey    schedule 08.11.2017
comment
@hotkey Inline может подойти для этих тестовых процедур, но я все еще не уверен, как будет выглядеть этот синтаксис. Я пытался, но я думаю, что я все еще не понимаю типы правильно. Не могли бы вы показать мне, как выглядел бы синтаксис, если бы все было встроено?   -  person sirksel    schedule 09.11.2017


Ответы (1)


Не совсем понятно, чего вы пытаетесь достичь. Если вы дадите более подробную информацию, мы можем предоставить лучший ответ. Тем не менее, следующий код, надеюсь, укажет вам правильное направление.

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 на самом деле использовался не как forEach, а как map. Это была основная проблема, поскольку вы использовали yield для вывода результатов, а не просто для возврата результатов. Если forEachFrom также собирались использовать из-за его побочных эффектов, его все еще можно использовать для этой цели.

Кроме того, у test не было причин принимать функцию в качестве параметра вместо того, чтобы просто принимать в качестве параметра вывод этой функции. Вызов buildSequence также был излишним, так как вы немедленно вызываете joinToString, который является терминальным и заставляет выполнять немедленные вычисления функции внутри buildSequence.

person Steven Waterman    schedule 19.03.2019