Roberto Zunino wrote:
Brian Hulley wrote:
because Haskell doesn't allow a superclass (or ancestor class)
method default to be redefined in a subclass.

How one would write instances? Using your Monad class, does
   instance Monad F where
      return = ...
      (>>=) = ...
automatically define an instance for Applicative?

Yes, but I'd make the method names be "call-site-bound" so the actual method that is called is determined by the set of instance decls and class decls visible at each particular call site, and any instances that are automatically created would be hidden by any explicitly defined instances that are visible.


If it does: What if there already is such an instance? Which one gets
used for (>>)? The user-defined one or the Monad default?

A possible proposal could be:
1) Class and instance decls would allow method implementations to be given for any methods in the class or any ancestor class.

2) Whenever an instance decl is visible there would always be a full set of instance decls for all ancestor classes, by supplementing the set of explicitly given instance decls that are visible by automatically generated implicit instance decls.

3) The most specific method implementation would always be chosen (ie prefer an explicit instance method over a class method and prefer a subclass method to a superclass method)

In particular rule 2) would mean that the actual method used depends on what's available at the call site which means that a Haskell program could no longer be thought of as being re-written into a single module before compilation, since the meaning of overloaded names would be determined by (CalledFromModule, Type) not just Type.

(The desire to hide instance decls or have different instance decls for the same type within the same program has come up before on the list but unfortunately I can't remember who posted something along these lines or when.)

Is separate
compilation still possible? (If there is no instance right now, one
might pop out in another module...)


I think it should still be possible because within a module, the overloadings would be determined by the set of explicitly defined instances in scope in that module. Various optimizations might be more tricky because the call site module associated with each overloaded name would need to be taken into account when inlining across module boundaries (ie a name used inside an inlined function needs to be resolved as if it had been used in the module where the function was defined not the module where the function is inlined).

For example:

   module A where
   import Proposed.Control.Monad

   data T a = T a
   instance Monad T

   [-# INLINE foo #-}
   foo :: a -> T a
   foo = return      -- uses Monad class default
                           -- which is inherited from the Applicative
                           -- class default

   module B where
   import A
   import Proposed.Control.Monad

   instance Applicative T where
       return x = retB x

   bar :: T a
   bar = return 'q'    -- would use (retB)

   zap :: T a
   zap = foo 'q'    -- would use (return) from A

A question is whether the extra difficulty in resolving overloadings (for human reader as well as complier) is worth the advantages of being able to get generated definitions for (>>) for Applicative and (fmap) for Functor from a single instance decl for (Monad.>>=) etc.

[Rearranged]
The class aliases proposal lists several similar shortcomings of the
current class system.
http://repetae.net/john/recent/out/classalias.html

IIUC the class alias proposal is about being able to group classes together and deal with them as a whole so similar issues of resolving overloadings arising from overlapping aliases/ explicit instance decls etc would arise (and I imagine the solutions would lie in similar directions).

Brian.
--
http://www.metamilk.com
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Reply via email to