Partial application

Space Age
Space Age in Scala
object SpaceAge {
  private val EARTH_SECONDS = 31_557_600.0
  private def calculate(orbitPeriod: Double, seconds: Double): Double =
    seconds / EARTH_SECONDS / orbitPeriod

  val onEarth = calculate(1, _)
  val onMercury = calculate(0.2408467, _)
  val onVenus = calculate(0.61519726, _)
  val onMars = calculate(1.8808158, _)
  val onJupiter = calculate(11.862615, _)
  val onSaturn = calculate(29.447498, _)
  val onUranus = calculate(84.016846, _)
  val onNeptune = calculate(164.79132, _)
}

This approach starts by defining the number of earth seconds in a year. Note the use of digit separators (_) makes long numbers more readable.

The calculate() method is defined as a regular function taking two parameters.

Following the calculate() method are bindings with the same names as the methods expected by the tests. The bindings are set to the calculate() method partially applied, with the second argument omitted. The calculate() method called with its first argument returns a function which takes the argument for seconds. So each binding is the calculate() method ready to accept its second argument.

The order of the parameters does not matter. The following definitions, with the parameters reversed, would also work

private def calculate(seconds: Double, orbitPeriod: Double): Double =
    seconds / EARTH_SECONDS / orbitPeriod

  val onEarth: Double => Double = calculate(_, 1)
  val onMercury: Double => Double = calculate(_, 0.2408467)

When a test calls one of the bindings with the seconds value, it is calling the partially applied calculate() function that is expecting its second argument. The partially applied function takes the seconds value and returns the result of the expression in the body of the partially applied function.

16th Aug 2024 · Found it useful?