In GHC Haskell, Map k v
has a type role declaration for k
to be nominal. This is because the user can otherwise coerce
k
to another type with the same representation but different Ord
instance, breaking the invariants.
However, I have some newtypes whose Ord
instances are inherited. In this case unsafeCoerce
seems to do the job (correct me if there are subtleties I don't know), but this completely turns off the typechecking for the coercion, which keeps me awake at night. In my specific use case, I have a type MyWrapper k
, and I would like to be able to declare some newtypes k1
-> k2
as admissible for safe coercion even when it is the argument of MyWrapper
. Is this possible? What are some other workarounds?
I'd say it makes sense to introduce a typeclass for this specific purpose. Not to actually do the conversion, just to alias a version of unsafeCoerce
restricted to the case where it actually is safe.
{-# LANGUAGE MultiParamTypeClasses #-}
class (Ord a, Ord b) => CompatibleOrd a b
-- no methods
instance CompatibleOrd YourBaseType YourNewtype
coerceKeysMonotonically :: (Coercible a b, CompatibleOrd a b)
=> Map a y -> Map b y
coerceKeysMonotonically = unsafeCoerce