Naresh Krishnamoorthy
Naresh Krishnamoorthy

Reputation: 331

Looking for best practice to dynamically compose functions in Scala

I am trying to write Scala code to get list of functions from a client code and compose it using chained approach and finally apply the composed function and i am able to make it.. But i feel like i am not doing it in a functional way since i am declaring a function variable with "var" in Test.scala(below) and keep composing functions on top of it. I believe there should be a better approach and any guidance and suggestion would help me

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)
    }
}

Client Code: Main.scala

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

Upvotes: 2

Views: 311

Answers (4)

Shanti Swarup Tunga
Shanti Swarup Tunga

Reputation: 641

You can get the result by chaining only one function

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)

output:

288

Upvotes: 1

Bogdan Vakulenko
Bogdan Vakulenko

Reputation: 3390

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

of use cats library if you need lazy evaluation

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

Upvotes: 4

If you want to avoid mutations the best (only?) way, is to create a modified copy of the data you want to mutate.
For example

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.

However, being honest, this design seems odd to me. Maybe, would not be better to have a list of functions, reduce it using andThen and finally applying the resulting function?

Upvotes: 2

Mario Galic
Mario Galic

Reputation: 48420

Similar functional composition can be achieved by repeated application of andThen like so:

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

Upvotes: 3

Related Questions