As a little anti-nausea med, I have this in my utilities.swift file for AoC:
func memoize<In: Hashable, Out>(_ f: @escaping (In) -> Out) -> (In) -> Out {
var memo: [In: Out] = [:]
return {
if let result = memo[$0] {
return result
} else {
let result = f($0)
memo[$0] = result
return result
}
}
}
which I used on day 12 as
let possibilities = memoize(_possibilities)
func _possibilities(_ record: Record) -> Int {
// snip...
// try if starting with a . or ?
let ifDotCount = record.tryEatDot().map(possibilities) ?? 0
// etc...
}
Of course, this is still a global memo dictionary variable. But it guarantees it's only used for memoizing that one function, and since _possibilities
is pure it's fairly principled.
It's not thread safe though, so if you try using this in Swift 6 you'd get an error – so you'd need to mark possibilities
as either @MainActor
or nonisolated(unsafe)
(for AoC leaderboard purposes only, of course).
p.s. congrats on placing on Day 12, @mayoff