Home > Blockchain >  Scala Function Chaining and handle failure
Scala Function Chaining and handle failure

Time:09-10

I have many functions in my code defined with return type as Either[Throwable, String] and all of them have one argument of type String. Three representative functions of my code are defined as:

  val f1 = (input: String) => {
    /* Processing from the input using a library in my actual code returns a Either[Throwable, String] */
    if (input == "a") Left(new Exception(input))
    else Right("Success")
  }

  val f2 = (input: String) => {
    if (input == "b") Left(new Exception(input))
    else Right("Success")
  }

  val f3 = (input: String) => {
    if (input == "c") Left(new Exception(input))
    else Right("Success")
  }

To chain the function outputs, I'm writing code like:

  def x(input: String) = f1(input) match {
    case Left(value) => Left(value)
    case Right(_) => f2(input) match {
      case Left(value) => Left(value)
      case Right(_) => f3(input)
    } 
  }

Since this is just three functions so this might look like a short code. However there are multiple such matches that are happening in my code, so it's a very long code. I am looking to avoid such a chaining.

I know that Scala has a way to chain functions like f1.andThen(f2).andThen(f3), however the problem is that in each andThen we need to pass the same argument, in this case being input. However I want to chain these functions so that if there is a Left output, it should not go to the next andThen.

I believe this can be simplified using Functional Programming, but I don't know where to start. Is there a way we can achieve this using Scala functional programming?

CodePudding user response:

If you have cats in scope, then all you need to do is this:

import cats.syntax.all._

val functions: List[String => Either[Throwable, Unit]] = List(
  // put your functions here.
)

val result: Either[Throwable, Unit] =
  functions.traverse_(f => f(input))

Otherwise, you may emulate it using this:

val init: Either[Throwable, Unit] = Right(())

functions.foldLeft(init) {
  case (acc, f) =>
    acc.flatMap(_ => f(input))
}
  • Related