Функция Memoization в Котлине

У меня есть существующий класс с методом экземпляра buildHierarchyUncached, подпись которого может быть найдена ниже.

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

Я хотел бы предоставить публичную функцию buildHiearchy, которая является memoized версией buildHierarchyUncached. Я могу приблизиться к тому, что хочу:

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

Который можно назвать:

 hierarchyService.buildHiearchy(businessDate) 

С помощью:

 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) } ) } } 

Я хотел бы иметь возможность объявить memoized функцию как функцию вместо свойства, которое не является огромной сделкой, хотя я думаю, что она помогает читаемости. Как это:

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

но это не компилируется: «Тип несоответствия. Требуемый узел. Найдено memoize».

Кроме того, почему это не компилируется?

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

По характеру проблемы вам нужно поле класса для хранения кеша (кэшированное значение или объект кэширования или делегат). Поэтому вы должны объявить val в классе где-то, так как функции не могут этого сделать.

Обратите внимание, что когда вы объявляете значение buildHiearchy , вы получаете две вещи в одном: вы сохраняете объект Memoize<..>(..) в поле класса и получаете функцию invoke() (объявленную где-то еще, но все же …) , Я не знаю, как вы можете объявить функцию и получить полевое хранилище без дополнительного синтаксиса.

Фрагмент кода использует устаревший синтаксис. Исправьте это (нет круглых скобок):

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

Следующее решение работает для функций с одним аргументом. Если вы хотите создать кэшированную версию функциональной bar вы просто объявляете ее так:

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

Реализация хранит кеш в закрытии, поэтому вам не нужно помещать его в выделенный класс:

 fun <X, R> makeFunctionCache(fn: (X) -> R): (X) -> R { val cache: MutableMap<X, R> = HashMap() return { cache.getOrPut(it, { fn(it) }) } }