
#14292: Coercing between constraints of newtypes -------------------------------------+------------------------------------- Reporter: Iceland_jack | Owner: (none) Type: feature request | Status: new Priority: normal | Milestone: Component: Compiler | Version: 8.2.1 Resolution: | Keywords: Operating System: Unknown/Multiple | Architecture: | Unknown/Multiple Type of failure: None/Unknown | Test Case: Blocked By: | Blocking: Related Tickets: | Differential Rev(s): Wiki Page: | -------------------------------------+------------------------------------- Comment (by RyanGlScott): I wouldn't say that this is rejected due to a fundamental limitation so much as a deliberate design choice. The immediate reason that the former program is rejected is due to roles. By default, all class parameters are given role `nominal`, so you can't coerce between `Num a` and `Num b` unless `a ~ b`. Why is the case? Even if `a` and `b` are representationally equal, there's absolutely no guarantee that their corresponding `Num` dictionaries are also representationally equal. After all, a `Num` instance for `USD` might do something crazy like `fromInteger _ = USD 42`. Defaulting class parameters to `nominal` is thus a conservative way to avoid the shenanigans that would unfold if you treated a `Num USD` dictionary as a `Num Int` one, or vice versa. Now you might object: "But I'm a careful programmer! I promise to only use `Num Int` and `Num USD` dictionaries that are representationally equivalent!" In that case, there is a fallback mechanism in the form of `IncoherentInstances`: {{{#!hs {-# Language ConstraintKinds #-} {-# Language GADTs #-} {-# Language IncoherentInstances #-} {-# Language RoleAnnotations #-} import Data.Coerce import Prelude hiding (Num(..)) newtype USD = USD Int data Dict c where Dict :: c => Dict c type role Num representational class Num a where -- ... instance Num Int instance Num USD num :: Dict (Num Int) -> Dict (Num USD) num = coerce }}} I hope it should be obvious from the name `IncoherentInstances` alone that this fallback carries significant risks. Use this trick at your own discretion. Does that answer the question satisfactorily? If so, please feel free to close the ticket. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/14292#comment:1 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler