lazy evaluation - Scala: partially evaluate a function and cache fixed values -


is there easy way cache fixed values of partially applied function, in pure functional way.

code sample:

scala> def f(x:int,y:int)={     def expensivecalculation(num:int)={         println("i've spent 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 lot of time(!) calculating square of 1 i've spent lot of time(!) calculating square of 2 res18: int = 5  scala> g(3) i've spent lot of time(!) calculating square of 1 i've spent lot of time(!) calculating square of 3 res19: int = 10 

but don't want expensivecalculation called 2 times num=1. since expensivecalculation side effect free, there no problem in saving results (please don't consider side effect of printing on output stream in sample code).

i can implement i'm looking using oop style saving state manually (though not clean if want write general reusable code it).

i think in fp every function side effect free, should easier achieve goal. can't think of strict limitation in using default behavior in purely functional language (except practical concerns amount of memory needed cache , etc).

you can leverage fact scala oop , fp language @ same time , functions in scala objects.

object cachedfunction extends app {    val f = new function2[int, int, int] {     def expensivecalculation(num: int) = {       println("i've spent 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) } 

prints:

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

i've changed f def val - allows f object "stores" function rather being method runs whole body every time. in case apply run every time , instance variables of function object preserved. rest oopish kind of way.

although can considered immutable caller because returned result not change on time it's not thread safe.you might want use sort of synchronized map storing cached values.

edit: after wrote googled "function memoization" , got these similar solutions. more generic though:

scala memoization: how scala memo work?

is there generic way memoize in scala?

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

apparently there in scalaz :)

edit:

the problem scala not eagerly evaluate arguments of function if function partially applied or curried. stores values of arguments. here example:

object cachedarg extends app {    def expensivecalculation(num: int) = {     println("i've spent lot of time(!) calculating square of " + num)     num * num   }    val ff: int => int => int = => b => expensivecalculation(a) + expensivecalculation(b)   val f1 = ff(1) // prints nothing    val e1 = expensivecalculation(1) // prints 1   val f: (int, int) => int = _ + expensivecalculation(_)   val g1 = f(e1, _: int)   g1(2) // not recalculate 1   g1(3) } 

prints:

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

this shows can still evaluate argument once manually , "save" partially applying function (or currying). think that's going after. have more convenient way can use approach:

object cachedfunction extends app {    val f = new function1[int, int => int] {     def expensivecalculation(num: int) = {       println("i've spent 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 eval of 1   g1(2)   g1(3) } 

prints:

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

however, in both last examples, memoizaition local function object. have reuse same function object work. unlike that, in first example memoizaition global scope function defined.


Comments

Popular posts from this blog

c# - Binding a comma separated list to a List<int> in asp.net web api -

Delphi 7 and decode UTF-8 base64 -

html - Is there any way to exclude a single element from the style? (Bootstrap) -