I'd do something like the following instead. Relying only on a Hasher
does not account for possible hash collisions, so I'd create a private container type that properly conforms to Hashable
and store that in the dictionary.
func memoize<each In: Hashable, Out>(_ factory: @escaping (repeat each In) -> Out) -> (repeat each In) -> Out {
var memo: [Container<repeat each In>: Out] = [:]
return { (pack: repeat each In) -> Out in
let container = Container(repeat each pack)
if let result = memo[container] {
return result
} else {
let result = factory(repeat each pack)
memo[container] = result
return result
}
}
}
private struct Container<each T> {
let value: (repeat each T)
init(_ value: repeat each T) {
self.value = (repeat each value)
}
}
extension Container: Equatable where repeat each T: Equatable {
static func == (lhs: Container<repeat each T>, rhs: Container<repeat each T>) -> Bool {
for (left, right) in repeat (each lhs.value, each rhs.value) {
guard left == right else { return false }
}
return true
}
}
extension Container: Hashable where repeat each T: Hashable {
func hash(into hasher: inout Hasher) {
for element in repeat each value {
hasher.combine(element)
}
}
}