Changes between Version 20 and Version 21 of IntrinsicSuperclasses

Aug 5, 2014 2:32:32 PM (5 years ago)

more chat, arising from discussion


  • IntrinsicSuperclasses

    v20 v21  
    99(More broadly, we have the recurrent problem of how to program defensively against progress. We may wish for benevolent evolution in the library, but we have to program against the library as it stands, and then the granting of our wishes breaks our code!)
     11Moreover, whether refactoring a legacy hierarchy or not, some subclasses give rise to default definitions for some of their superclasses. E.g., `Ord` can induce a standard definition of `Eq`, `Monad` induces `Applicative`, `Applicative` and `Traversable` both induce `Functor`. In these cases, we commonly just want the obvious default implementations and it is a nuisance to spell them out longhand.
    1113=== Requirement 1: Some instance definitions in source code should generate multiple internal instances. ===
    8991Note that explicit `Functor` instances do not have a default implementation of `fmap` (that being rather the point of such instances), but that explicit `Applicative` and `Monad` would, under this proposal.
     93The imagined solution delivers the instance of the intrinsic superclass by default, largely motivated by the refactoring issue, which has had nontrivial negative consequences for the evolution of the library, the Functor-Applicative-Monad hierarchy being a case in point. If we were gifted with foresight, we might prefer an "opt-in" approach, where default instances can be generated cheaply but not in total silence.
     95Many default superclass instances are likely to define some but not all of the superclass members. E.g., we can make `return` a member of `Applicative`: we would then expect a `Monad` instance to define `return` but to acquire a default definition of `<*>`. An opt-in notation would need to (and could) say more than `deriving Applicative`.
    498504  * `deriving (Ord, Eq) gives `Ord a => Ord (Square a)` and `Eq a => Eq (Square a)`, with no pre-emption warning;
    499505  * `deriving (Ord - Eq)` gives just `Ord a => Ord (Square a)` requiring a separate hand-rolled `Eq (Square a)` instance.
     510== Counterfactuals ==
     512Arising from discussion, further modifications are worth considering, if only to step back from them.
     514=== Liberalization 7 Use type inference to disambiguate member distribution. ===
     516We could imagine permitting
     518class Foo x where
     519  foo :: x -> x
     521class (instance Foo x, instance Foo y) => Goo x y where
     522  goo :: x -> y
     524and if we saw
     526instance Goo Int Bool where
     527  foo x = 3
     528  foo x = True
     529  goo = (0 <)
     531it would be obvious that we meant
     533instance Foo Int where
     534  foo x = 3
     535instance Foo Bool where
     536  foo x = True
     537instance Goo Int Bool where
     538  goo = (0 <)
     540because type information tells us which `foo` belongs where.
     542That is, we could adopt a policy of complaining only if type inference fails to disambiguate the distribution of members to internal instances.
     544We might need enough notation to opt out of `Foo x` but not `Foo y`. More explicit notation will be necessary
     545whenever the given definitions. E.g.,
     547instance Goo Int Bool where
     548  foo 0 = 3
     549  foo x = x
     550  foo x = True
     551  goo = (0 <)
     553does not establish in which instance the `foo x = x` line belongs.
     555Of course, one could reject such programs as ambiguous, but certainly, the static semantics of such a system is far more subtle than the present proposal.
     557=== Liberalization 8 Make superclasses intrinsic by default. ===
     559We could drop the use of `instance` to mark which superclasses are intended as intrinsic. Again adopting a complain-on-ambiguity semantics, we could generate a superclass instance automatically from a subclass instance whenever there is at least one candidate member definition: either a default in the subclass, or an explicit definition in the subclass instance. So
     561class Bing x where
     562  bing :: x
     563class Bing x => Bong x where
     564  bong :: x
     565instance Bong Int where
     566  bing = 1
     567  bong = 0
     569generates a `Bing Int` instance too, as does
     571class Bing x where
     572  bing :: x
     573class Bing x => Bong x where
     574  bong :: x
     575  bing = bong
     576instance Bong Int where
     577  bong = 0
     581class Bing x where
     582  bing :: x
     583class Bing x => Bong x where
     584  bong :: x
     585instance Bong Int where
     586  bong = 0
     588generates only a `Bong Int` instance (rather than an empty `Bing Int` instance).
     590Such a proposal would require a little more subtlety to determine which instances are generated, but might be sustainable.
     592Certainly, it would still require authors of client code to be aware of whether a given class is likely to generate superclass instances. If I define some rather special purpose library with
     594class Eq x => WhizzBanger x where
     595  whizz :: x -> x -> x
     596  bang  :: x -> Bool
     598then clients need to know whether their `WhizzBanger` instances need to bring an `Eq` instance or will get one. This liberalization cuts the `instance` notation in class declarations but not the necessity to be aware of what it makes explicit.