Home > Software design >  How to compose partial functions with multiple parameters in Scala
How to compose partial functions with multiple parameters in Scala

Time:12-27

    val f1 = (x: Int) => x match {
      case x1 => x * 2
    }
    
    val f2 = (x: Int, y: Int) => (x, y) match {
      case (x1, y1) => x1   y1
    }
    
    val f3 = f1.compose(f2)

Expecting f3 to be a partial function from (Int, Int) => Int but I get the following error

Found:    (f2 : (Int, Int) => Int)
Required: Any => Int

CodePudding user response:

As the documentation suggests, compose specifically composes two instances of Function1, that is two instances of a unary function.

If you want to keep your code as is, the way to do this is

f1 andThen f2.curried

If you look at the documentation closely

compose returns a new function f s.t. f(x) == apply(g(x))

andThen returns a new function f s.t. f(x) == g(apply(x))

Note the difference in order of application. Yes, I know the naming is rather is confusing.

Edit: It is confusing which way you want these to apply. The other way around is provided in Jorg's answer.

CodePudding user response:

Both scala.Function1.compose and scala.PartialFunction.compose only take functions as parameters which have a single parameter. But f2 has two parameters, therefore, it is not type-compatible with the parameter type of compose.

You can convert f2 to a single-parameter function which takes its parameters as a scala.Tuple using the scala.Function2.tupled method:

val f3 = f1.compose(f2.tupled)

Note: f3 is now a Function1[Tuple2[Int, Int], Int] aka ((Int, Int)) => Int, i.e. it needs to be applied like this:

f3((2, 3))

To turn it into a Function2[Int, Int, Int] aka (Int, Int) => Int, you can use the scala.Function.untupled method:

val f4 = Function.untupled(f3)

Scastie link

Also note that neither f1 nor f2 are scala.PartialFunctions. f1 is a scala.Function1[Int, Int] aka (Int) => Int and f2 is a scala.Function2[Int, Int, Int] aka (Int, Int) => Int.

  • Related