I was using ‘some’ pretty neutrally; I’m aware of what instances it generates and that there’s a lot of engineering behind it.
The real issue here is the reliance on an unspecialised typeclass method in performance critical (?) code. Rather than the non-zero-cost but still ~trivial runtime call, I would be more concerned about the barrier to optimisation imposed by its opacity to the simplifier.
Regardless, as the author of bluefin, you’re the one who’s in a position to determine what new coercion primitives the library should utilise to be performant, and which can be exposed without compromising the safety of the interface. One rather direct candidate would be:
coerceHandle :: (Handle h, e :> es) => h e -> h es
coerceHandle h = unsafeCoerce h
The original typeclass method would then be treated like a compile-time “proof”; it can be renamed, hidden in an opaque newtype, given a -Wx-not-for-direct-use
warning, whatever.
Coercible
is mandatorily symmetric. This could pose some difficulties if you’re trying to implement asymmetric coercions by restricting it from within. It does not when building atop.
You’ve already seen me at it, composing one-way coercions with coerce
, or using Coercible
constraints as evidence in fsub
—it’s just another source of magic primitives.
Regardless, since this discussion has gone on rather too long and code speaks louder than words, I’ve elected to write up a full implementation of how I might actually approach this in the general case: Generalised Coercible · GitHub
Presumably @clinton would also be interested. I’ll conclude by quoting myself, since it seems to bear repeating:
We could obviously do better if the magic and automation were baked into GHC, and perhaps one day it will be. In the mean time, we have to make do with something on this level.