Кеширование с использованием функциональных обратных вызовов / прокси-шаблонов реализации scala
Как реализовать кеш с помощью функционального программирования
Несколько дней назад я сталкивался с обратными вызовами и реализацией шаблонов прокси с использованием scala. Этот код должен применять только внутреннюю функцию, если значение отсутствует на карте. Но каждый раз, когда карта повторно инициализируется, а значения исчезают (что кажется абсурдным.
Как использовать один и тот же кеш снова и снова между различными вызовами функций
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
}
3 ответа
Я вижу, что вы пытаетесь сделать здесь, причина этого не в том, что каждый раз, когда вы звоните memoizedDoubler
это первый звонок memorize
, Вы должны объявить memoizedDoubler
как val
вместо def
если ты хочешь это только позвонить memoize
один раз.
val memoizedDoubler = memoize( (key:Int) => {
println("Evaluating...")
key*2
})
Этот ответ имеет хорошее объяснение разницы между def
а также val
, /questions/47811212/razlichiya-mezhdu-etimi-tremya-sposobami-opredeleniya-funktsii-v-scala/47811220#47811220
Разве вы не объявляете новый Map
за вызов?
def memoize(function: Function[Int, Int] ):Function[Int,Int] = {
val cache = HashMap[Int, Int]()
вместо того, чтобы указывать один на экземпляр Aggregator
?
например
class Aggregator{
private val cache = HashMap[Int, Int]()
def memoize(function: Function[Int, Int] ):Function[Int,Int] = {
Чтобы ответить на ваш вопрос:
Как реализовать кеш с помощью функционального программирования
В функциональном программировании нет понятия изменчивого состояния. Если вы хотите что-то изменить (например, кеш), вам нужно вернуть обновленный экземпляр кеша вместе с результатом и использовать его для следующего вызова.
Вот модификация вашего кода, которая следует этому подходу. function
рассчитать значения и cache
включен в Aggregator
, когда memoize
вызывается, он возвращает кортеж, который содержит результат вычисления (возможно, взятый из кэша) и новый Aggregator
это должно быть использовано для следующего звонка.
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)
}
}
Это печатает:
Evaluating...2
Evaluating...3