Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Memoization Function In Kotlin

I have an existing class with an instance method buildHierarchyUncached whose signature can be found below.

private fun buildHierarchyUncached(date: LocalDate): Node { ... }

I would like to provide a public function buildHiearchy that is a memoized version of buildHierarchyUncached. I can get close to what I want:

val buildHiearchy = Memoize<LocalDate, Node>({buildHierarchy(it)})

Which can be called like:

hierarchyService.buildHiearchy(businessDate)

Using:

class Memoize<I, O>(val func: (I) -> O): (I) -> O{
  val cache = hashMapOf<I, O>();
  override fun invoke(p1: I): O {
    return cache.getOrPut(p1, { func(p1) } )
  }
}

I would like to be able to declare the memoized function as a function instead of a property, which is not a huge deal, though I think it helps readability. Like this:

fun buildHierarchy(date: LocalDate): Node = Memoize<LocalDate, Node>({ buildHierarchyUncached(it)})

but that doesn't compile: "Type mismatch. Required Node. Found memoize."

Also, why doesn't this compile?

val buildHiearchy = Memoize<LocalDate, Node>({(date) -> buildHierarchy(date)})
like image 651
Brandon Johnson Avatar asked Feb 10 '16 00:02

Brandon Johnson


2 Answers

You can achieve your goal with a Map.computeIfAbsent, it will look something like that:

val map = HashMap<String, Any>()

fun doSomething():Any{
    return map.computeIfAbsent("functionKey") { 
        // do your calculation here 
    }
}

This way, the calculation will be executed only once and stored in the map

like image 135
Ilya Gazman Avatar answered Sep 21 '22 23:09

Ilya Gazman


The following solution works for single-argument functions. If you want to created a cached version of the function bar you simply declare it like this:

val cachedBar = makeFunctionCache({ bar(it) })

The implementation stores the cache in a closure so that you don't need to put it in a dedicated class:

fun <X, R> makeFunctionCache(fn: (X) -> R): (X) -> R {
    val cache: MutableMap<X, R> = HashMap()
    return {
        cache.getOrPut(it, { fn(it) })
    }
}
like image 31
Elias Mårtenson Avatar answered Sep 17 '22 23:09

Elias Mårtenson