
#8370: Ranked Instances -------------------------------------+------------------------------------ Reporter: wvv | Owner: Type: feature request | Status: closed Priority: normal | Milestone: Component: Compiler | Version: 7.6.3 Resolution: invalid | Keywords: Operating System: Unknown/Multiple | Architecture: Unknown/Multiple Type of failure: None/Unknown | Difficulty: Unknown Test Case: | Blocked By: Blocking: | Related Tickets: -------------------------------------+------------------------------------ Comment (by wvv): I'm really deeply appreciated ! And I'm really sorry if my examples are not understandable and my explanation isn't clearly enough (( Here is a background: the main power of Haskell is type-classes and their implementation: instances. So, Haskell is interested to have as much instances as it can for any cases. Unfortunately we can't have a lot of instances - they became to overlap each other. In many cases Overlapping Instances doesn't solve our problems. GHC add "default" instances. But it is a partially solved problem. For now we are capable to write next: {{{ instance Monad m => Functor m where fmap = liftM instance Applicative m => Functor m where fmap f x = pure f <*> x }}} But we cannot add them of overlapping reason. Both of them not only overlap with any concrete instance but each other. "Defaulting" and overlapping won't help us to solve this. All (except hidden with "defaulting") superclass' instances like: {{{ instance Child a => Parent a where .. }}} are forbidden == (1) == Ranked Instances allow us to create and use all `Child a => Parent a` superclass' instances {{{ class Applicative f where ... --without "Functor f=>", it is a misfeature instance rank 15. Monad m => Functor m where fmap = liftM instance rank 16. Applicative m => Functor m where fmap f x = pure f <*> x }}} Compiler try use all 0-ranked instances, then all 1-ranked, then ..., then all 14-ranked, then all 15-ranked. If instances overlap in any rank-layer, it is an error. Our 2 instances are in different layers, so we have no overlapping. All user's instances by default are 0-ranked. So if user create data, add 2 instances: Monad and Applicative, {{{ data D a ... instance Monad D where ... class Applicative f where ... --without "Functor f=>" instance Applicative D where ... }}} and not Functor, but try to use `fmap` {{{ foo = (+) `fmap` D 1 }}} compiler use (Monad m => Functor m) instance, reason - lower rank, than (Applicative m => Functor m). If user define his own instance Functor data, {{{ instance {- ranked 0. -} Functor D where .. }}} it will be 0-ranked instance, so compiler use his instance, not superclass' instance (with much higher rank). ''A lot of Child2Parent superclass' instances are the unique feature of this extension! '' == (2) == Ranked Instances allow us to get rid of default instances, but save all capabilities of it. Even more - with Ranked Instances is allowed to use several default-like instances (outside of class) {{{ class ToJSON a where toJSON :: a -> Value default instance (Generic a, GToJSON (Rep a)) => ToJSON a where toJSON = genericToJSON defaultOptions }}} is the same as {{{ class ToJSON a where toJSON :: a -> Value instance rank 10. (Generic a, GToJSON (Rep a)) => ToJSON a where toJSON = genericToJSON defaultOptions instance rank 11. (Data a) => ToJSON a where ... }}} Here we have 2 default-like instances! If we wish to add third, I dunno, "Typeable a=> ToJson a" we still could add it (with higher rank). ''We'll have with Ranked Instances much more, then with default instances! '' == (3) == Ranked Instances are powerful enough to use them instead of both Overlapping Instances and Incoherent Instances. {{{ instance rank 3. C a Int Bool where ... instance rank 2. C Int Int a where ... instance rank 1. C a Bool a where ... instance rank 0. C Bool a Bool where ... }}} Neither Overlapping Instances, nor Incoherent Instances can't help us in this situation. With Ranked Instances, Compiler try to 1) 0-rank: look if first and third args are Bool 2) if no, 1-rank: look if second arg is Bool 3) if no, 2-rank: look if first and second args are Int 4) if no, 3-rank: look if second argument is Int and third is Bool 5) if no, throw an error ''We'll have with Ranked Instances much more, then Overlapping Instances and Incoherent Instances together! '' == (S) == If we summarize, Ranked Instances is a very powerful extension! It is easy to implement, easy to use and easy to read the code. It is compatible with all old code and other extensions. It is a step forward, not aside. It allows to write more generic code. It helps to get rid of boilerplate. I suppose, for now my proposal looks much more clearly. If it is something unclear, I give more explanation. -- Ticket URL: http://ghc.haskell.org/trac/ghc/ticket/8370#comment:2 GHC http://www.haskell.org/ghc/ The Glasgow Haskell Compiler