Ищете лучшие практики для динамического создания функций в Scala

#scala

#scala

Вопрос:

Я пытаюсь написать код Scala, чтобы получить список функций из клиентского кода и составить его, используя цепной подход, и, наконец, применить составленную функцию, и я могу это сделать.. Но я чувствую, что делаю это не функционально, поскольку я объявляю функциональную переменную с «var» в Test.scala (ниже) и продолжаю создавать функции поверх нее. Я считаю, что должен быть лучший подход, и любые рекомендации и предложения помогут мне

Test.scala

 case class Test(val int: Int){
  private final var function : Int => Int = (i: Int) => i
  def composeFunction( f: Int => Int)   : this.type = {
   function = function.andThen(f);
        this;
    }
  def applyFunction : Int = {
        function(int)
    }
}
 

Клиентский код: Main.scala

 val c = new Test(6)
  .composeFunction((i: Int) => i *2)
  .composeFunction((i: Int) => i *4)
  .composeFunction((i: Int) => i *6)
  .applyFunction
 

Комментарии:

1. Я объявил функцию с именем «function» в Test.scala с поведением по умолчанию ((i: Int) => i), потому что, если клиент не вызывает «composeFunction», тогда «функция» должна выводить входное значение как есть

Ответ №1:

 val c = Some(6)
  .map((i: Int) => i *2)
  .map((i: Int) => i *4)
  .map((i: Int) => i *6)
  .get
 

используйте библиотеку cats, если вам нужна отложенная оценка

 val lazyEval = Eval.later(6)
  .map((i: Int) => i *2)
  .map((i: Int) => i *4)
  .map((i: Int) => i *6)
  .value
 

Ответ №2:

Аналогичная функциональная композиция может быть достигнута путем многократного применения A):T1=>A» rel=»nofollow noreferrer»> andThen подобных:

 val c = ((i: Int) => i * 2) andThen ((i: Int) => i * 4) andThen ((i: Int) => i * 6)
c(6) // res0: Int = 288
 

Ответ №3:

Если вы хотите избежать мутаций, лучше всего (только?)способ заключается в создании измененной копии данных, которые вы хотите изменить.
Например

 final case class Test(int: Int, function: Int => Int = identity){
  def composeFunction(f: Int => Int): Test =
    this.copy(function = this.function.andThen(f))

  def applyFunction: Int =
    function(this.int)
}

val c = Test(6)
  .composeFunction(i => i * 2)
  .composeFunction(i => i * 4)
  .composeFunction(i => i * 6)
  .applyFunction // 288.
 

Однако, честно говоря, этот дизайн кажется мне странным.
Может быть, не было бы лучше иметь список функций, сократить его с помощью andThen и, наконец, применить результирующую функцию?

Комментарии:

1. Наличие его в виде списка было моим первым вариантом, но я хотел сохранить порядок функций, который присутствует в клиентском коде.. Я боюсь, что наличие функций в списке изменит порядок.. ListBuffers сохраняет порядок?

2. Неизменяемый List в Scala сохраняет порядок, изменяемый ListBuffer также сохраняет порядок (особенно потому, что под капотом a ListBuffer находятся два неизменяемых Lists ) . Так что да, вам не стоит беспокоиться об этом.

Ответ №4:

Вы можете получить результат, связав только одну функцию

 case class Test(int: Int){
   def applyFunction(f: Int => Int): Test = {
   this.copy(f(int))
   }
}

// test
val c = Test(6)
.applyFunction((i: Int) => i * 2)
.applyFunction((i: Int) => i * 4)
.applyFunction((i: Int) => i * 6)
.int

println(c)
 

вывод:

 288