Стиль CPS для вызовов функций в стиле связанного списка

Я пытаюсь преобразовать следующий код в стиль передачи продолжения. Первоначально код возвращал String, поэтому я изменил его, чтобы вызвать лямбду продолжения, которая принимает String. Мне интересно, как удалить поле next и вместо этого использовать стиль CPS.

class Foo(val x: Double) {
  var next: Foo = _

  def bar(y: Double, returnLambda: (String => Unit)): Unit = {
    if (x * y > 0) {
      returnLambda("Bad")
    } else if (next == null) {
      returnLambda("Good!")
      next = new Foo(y)
    } else {
      next.bar(y, returnLambda)
    }
  }
}

person Node.JS    schedule 13.12.2018    source источник


Ответы (1)


Похоже, вы создаете односвязный список из Foo значений; новые значения добавляются в конец списка, пока знак нового значения отличается от существующего значения.

При функциональном подходе вы не стали бы встраивать управление списком в объект в списке. Вместо этого вы должны поддерживать список отдельно, var next: List[Foo], и выполнять добавление с помощью:

if ( next.all( _ * y <= 0) )
  returnLambda("Bad")
else {
  returnLambda("Good")
  next = next :+ Foo(y)
}

Поскольку мы упростили манипулирование списками, использование CPS теряет свои преимущества; вы можете просто вернуть строку «Хорошо» или «Плохо».

Предполагая, что вам действительно нужен CPS, вы можете удалить поле next, переместив его в сопутствующий объект:

object Foo {
  val listOfFoo: ListBuffer[Foo] = ListBuffer[Foo].empty

  def bar(y: Double,  returnLambda: (String => Unit)): Unit = 
    if ( listOfFoo.all(_ * y <= 0) )
      returnLambda("Bad")
    else {
      listOfFoo += Foo(y)
      returnLambda("Good")
    }
}
person Bob Dalgleish    schedule 14.12.2018