SwiftUI has this exact same issue. What it does is make a best effort to compare the function values (and all values, really) by memcmp, because all Swift types today currently guarantee that they're equivalent if they're bitwise-identical, tries to dynamically find Equatable
conformance if that fails, and otherwise assumes it needs to update. That works well enough in our experience, and it will work even better over time as the compiler improves to reduce reabstractions and specialize away closures in more situations.
As far as long-term directions for equatable closures, I think a good approach would be to turn function types into generic constraints, like they are in Rust, and allow closures to be treated as anonymous types, which would allow:
func foo<T: Equatable & () -> ()>(_: T)
to not only take a closure with equatable context, but also unbox the context, which would be useful for performance to be able to store it inline in composed types.