If you don't care about functions and you're fine with closures, you can already implement the mentioned LRU cache with property wrappers:
@propertyWrapper
class LRUCache<Parameter, Result> where Parameter: Hashable {
let base: (Parameter) -> Result
var cache: [Parameter: Result] = [:]
var cacheInfo = (hits: 0, misses: 0)
var wrappedValue: (Parameter) -> Result {
return { parameter in
if let cachedResult = self.cache[parameter] {
self.cacheInfo.hits += 1
return cachedResult
} else {
self.cacheInfo.misses += 1
let result = self.base(parameter)
self.cache[parameter] = result
return result
}
}
}
var projectedValue: String {
"Cache info: \(cacheInfo.hits) hits, \(cacheInfo.misses) misses, current size \(cache.count)"
}
init(wrappedValue function: @escaping (Parameter) -> Result) {
self.base = function
}
}
This example requires a function accepting a single parameter. With variadic generics it could be generalized. For simplicity the projected value returns the associated cache infos.
Python's lru_cache
:
@lru_cache(maxsize=None)
def fib(n):
if n < 2:
return n
return fib(n-1) + fib(n-2)
>>> [fib(n) for n in range(16)]
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> fib.cache_info()
CacheInfo(hits=28, misses=16, maxsize=None, currsize=16)
My attempt:
struct Main {
@LRUCache static var fib: (Int) -> Int = { (n: Int) -> Int in
if n < 2 { return n }
return Main.fib(n - 1) + Main.fib(n - 2)
}
}
>>> (0...15).map(Main.fib)
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610]
>>> Main.$fib
Cache info: 28 hits, 16 misses, current size 16