haskelltypesghccoercionnewtype

Admissble type role overrides


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?


Solution

  • 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