Scala composition of partially-applied functions

42 views Asked by At

I'd like to be able to compose functions from partially-applied functions. I.e. something like this:

def average(data: Seq[Option[Double]]): Option[Double] = {
  val numbers = data.flatten
  numbers match {
    case ns if ns.length == 0 => None
    case ns => Some(ns.sum / ns.length)
  }
}

def roundHalfUp(d: Double, rounding: Int): Double = {
  BigDecimal.apply(d).setScale(rounding, BigDecimal.RoundingMode.HALF_UP).doubleValue
}

def round(rounding: Int, number: Option[Double]): Option[Double] = {
  number match {
    case None => None
    case Some(n) => Some(roundHalfUp(n, rounding))
  }
}


val f = average andThen round(2)

f(List(1.23, 2.242, 3.345))

But I can't get the assignment of the composed function to work. I appreciate to coerce the functions I need parameter placeholders, i.e. val f = average(_) andThen round(2,_) but no matter what syntax I try doesn't work.

Could anyone advise on the correct syntax, or an alternative approach. This is supposed to be functionality for a simple design specific language so the simpler the better.

1

There are 1 answers

4
David Regan On

I worked it out!

I need to define the round function like this:

def round(rounding: Int)(number: Option[Double]): Option[Double] = {
  number match {
    case None => None
    case Some(n) => Some(roundHalfUp(n, rounding))
  }
}

and then I can lift the methods to functions (using parameter _):

val r = round(2) _
val a = average _

val f = a andThen r

f(List(1.23, 2.242, 3.345))

Or, without the intermediat variables,

val f = (average _) andThen (round(2) _)