2016-04-12 8 views
2

Wie Cache funktionale Programmierung vor

Ein paar Tage mit implementieren kam ich über Rückrufe und Proxy-Muster Implementierung scala verwenden. Dieser Code sollte nur innere Funktion anwenden, wenn der Wert nicht in der Karte ist. Aber jedes Mal Karte neu initialisiert und Werte sind verschwunden (die obivous scheint.Cache mit Hilfe der funktionellen Rückrufe/Proxy-Muster Implementierung scala

Wie gleichen Cache wieder verwenden und wieder zwischen den verschiedenen Funktionsaufrufe

class Aggregator{ 
    def memoize(function: Function[Int, Int]):Function[Int,Int] = { 
    val cache = HashMap[Int, Int]() 
    (t:Int) => { 
     if (!cache.contains(t)) { 
     println("Evaluating..."+t) 
     val r = function.apply(t); 
     cache.put(t,r) 
     r 
     } 
     else 
     { 
     cache.get(t).get; 
     } 
    } 
    } 

    def memoizedDoubler = memoize((key:Int) => { 
    println("Evaluating...") 
    key*2 
    }) 
    } 

object Aggregator { 

    def main(args: Array[String]) { 
    val agg = new Aggregator() 
    agg.memoizedDoubler(2) 
    agg.memoizedDoubler(2)// It should not evaluate again but does 
    agg.memoizedDoubler(3) 
    agg.memoizedDoubler(3)// It should not evaluate again but does 

} 
+0

Put 'cache' außerhalb der Funktion. – Dima

Antwort

1

Ich sehe, was Sie versuchen, hier zu tun, der Grund, dass es nicht funktioniert, dass jedes Mal, wenn Sie anrufen memoizedDoubler es erste memorize anruft. Sie müssen memoizedDoubler als val anstelle von def deklarieren, wenn Sie nur memoize einmal aufrufen möchten.

val memoizedDoubler = memoize((key:Int) => { 
    println("Evaluating...") 
    key*2 
    }) 

Diese Antwort hat eine gute Erklärung für den Unterschied zwischen def und val. https://stackoverflow.com/a/12856386/37309

1

Sind Sie nicht ein neues Map pro erklären Aufruf?

def memoize(function: Function[Int, Int]):Function[Int,Int] = { 
    val cache = HashMap[Int, Int]() 

anstatt Angabe eine pro Instanz von Aggregator ?

z.B.

class Aggregator{ 
    private val cache = HashMap[Int, Int]() 
    def memoize(function: Function[Int, Int]):Function[Int,Int] = { 
+0

Ein Feld, das eine änderbare Auflistung innerhalb einer Methode darstellt. ** ist das eine gute Idee für verteilte Programme wie Funken ** –

+0

Bit verwirrt. Sie können kein Feld innerhalb einer Methode deklarieren –

0

Um Ihre Frage zu beantworten:

Wie Cache mit der funktionalen Programmierung

In der funktionalen Programmierung gibt es kein Konzept von wandelbaren Zustand implementieren. Wenn Sie etwas ändern möchten (wie Cache), müssen Sie die aktualisierte Cache-Instanz zusammen mit dem Ergebnis zurückgeben und für den nächsten Aufruf verwenden.

Hier ist die Änderung Ihres Codes, die diesem Ansatz folgt. function zur Berechnung von Werten und cache ist in Aggregator integriert. Wenn memoize aufgerufen wird, gibt es ein Tupel zurück, das das Berechnungsergebnis (möglicherweise aus dem Cache) und das neue Aggregator enthält, das für den nächsten Aufruf verwendet werden soll.

class Aggregator(function: Function[Int, Int], cache:Map[Int, Int] = Map.empty) { 

    def memoize:Int => (Int, Aggregator) = { 
    t:Int => 
     cache.get(t).map { 
     res => 
      (res, Aggregator.this) 
     }.getOrElse { 
     val res = function(t) 
     (res, new Aggregator(function, cache + (t -> res))) 
     } 
    } 
} 

object Aggregator { 

    def memoizedDoubler = new Aggregator((key:Int) => { 
    println("Evaluating..." + key) 
    key*2 
    }) 


    def main(args: Array[String]) { 
    val (res, doubler1) = memoizedDoubler.memoize(2) 
    val (res1, doubler2) = doubler1.memoize(2) 
    val (res2, doubler3) = doubler2.memoize(3) 
    val (res3, doubler4) = doubler3.memoize(3) 
    } 
} 

Diese Drucke:

Evaluating...2 
Evaluating...3 
Verwandte Themen