Scala: partially evaluate a function and fix fixed values

Is there an easy way to cache fixed values ​​of a partially applied function in a purely functional form.

Code example:

scala> def f(x:Int,y:Int)={
    def expensiveCalculation(num:Int)={
        println("I've spent a lot of time(!) calculating square of "+num)
        num*num
    }
    lazy val x2=expensiveCalculation(x)
    lazy val y2=expensiveCalculation(y)
    lazy val r=x2+y2
    r
}

scala> def g=f(1,_:Int)

scala> g(2)
I've spent a lot of time(!) calculating square of 1
I've spent a lot of time(!) calculating square of 2
res18: Int = 5

scala> g(3)
I've spent a lot of time(!) calculating square of 1
I've spent a lot of time(!) calculating square of 3
res19: Int = 10

But I do not want the expensive calculator to be called twice for num=1. Since an expensive calculator is a side effect, there is no problem saving the results (please do not consider the side effect of printing in the output stream in my sample code).

I can implement what I am looking for using OOP style, maintaining state manually (although it is not very clean if you want to write general reusable code for it).

, FP, , . ( , , ..).

+4
2

, Scala OOP FP Scala .

object CachedFunction extends App {

  val f = new Function2[Int, Int, Int] {
    def expensiveCalculation(num: Int) = {
      println("I've spent a lot of time(!) calculating square of " + num)
      num * num
    }

    var precomputed: Map[Int, Int] = Map()

    def getOrUpdate(key: Int): Int =
      precomputed.get(key) match {
        case Some(v) => v
        case None =>
          val newV = expensiveCalculation(key)
          precomputed += key -> newV
          newV
      }

    def apply(x: Int, y: Int): Int =
      getOrUpdate(x) + getOrUpdate(y)
  }

  def g = f(1, _: Int)

  g(2)
  g(3)
  g(3)
  f(1, 2)
}

:

I've spent a lot of time(!) calculating square of 1
I've spent a lot of time(!) calculating square of 2
I've spent a lot of time(!) calculating square of 3

f def val -, f , "" , , . apply, . - OOPish.

, , . , - .

EDIT: , , googled " memoization" . :

Scala Memoization: Scala ?

memoize Scala?

http://eed3si9n.com/learning-scalaz-day16

-, Scalaz - :)

EDIT:

, Scala , . . :

object CachedArg extends App {

  def expensiveCalculation(num: Int) = {
    println("I've spent a lot of time(!) calculating square of " + num)
    num * num
  }

  val ff: Int => Int => Int = a => b => expensiveCalculation(a) + expensiveCalculation(b)
  val f1 = ff(1) // prints nothing

  val e1 = expensiveCalculation(1) // prints for 1
  val f: (Int, Int) => Int = _ + expensiveCalculation(_)
  val g1 = f(e1, _: Int)
  g1(2) // does not recalculate for 1 obviously
  g1(3)
}

I've spent a lot of time(!) calculating square of 1
I've spent a lot of time(!) calculating square of 2
I've spent a lot of time(!) calculating square of 3

, "" , ( ). , . , :

object CachedFunction extends App {

  val f = new Function1[Int, Int => Int] {
    def expensiveCalculation(num: Int) = {
      println("I've spent a lot of time(!) calculating square of " + num)
      num * num
    }

    def apply(x: Int) =
      new Function[Int, Int] {
        val xe = expensiveCalculation(x)

        def apply(y: Int) = xe + expensiveCalculation(y)
      }
  }

  val g1 = f(1) // prints here for eval of 1
  g1(2)
  g1(3)
}

I've spent a lot of time(!) calculating square of 1
I've spent a lot of time(!) calculating square of 2
I've spent a lot of time(!) calculating square of 3

memoizaition . . , memoizaition , .

+3

:

lazy val _f=  scala.collection.mutable.Map[Int, Int]()
def f(x: Int)(y: Int) = {
  def expensiveCalculation(num: Int) = {
    println("I've spent a lot of time(!) calculating square of " + num)
    num * num
  }
  def _cached(a:Int) =_f.getOrElseUpdate(a, expensiveCalculation(a))

  lazy val r = _cached(x)+_cached(y)
  r
}
val g=f(1)_
g(2)
g(3)
+1

All Articles