Předmět: | Re: Pointed and Traversable |
---|---|
Datum: | Fri, 30 Aug 2013 16:59:45 +0200 |
Od: | Petr Pudlák <petr.mvd@gmail.com> |
Komu: | Edward Kmett <ekmett@gmail.com> |
Kopie: | Henning Thielemann <schlepptop@henning-thielemann.de>, Frantisek Farka <ffarka@gmail.com> |
True, that's an important issue to solve, I'll have to think about it. One idea that emerges is to borrow some concepts from OOP/Java and to distinguish "interface"-like type classes that have no defaults (just the ones we have now) and "class"-like type classes that can have defaults. And "class"-like could "descend" only from at most one other "class"-like type class. (This is perhaps somewhat similar to http://repetae.net/recent/out/classalias.html, which distinguishes classes from class aliases.)I can't speak well to SHE's implementation but there are a few tensions in the design space of how to handle default superclass instances in a language like Haskell that makes them not perfectly solve the issue that Haskell generally sucks at dealing with deep accurate typeclass hierarchies.
1.) When you have a complex lattice of types rather than a linear chain, you're going to get a lot of ways to derive the common default functionality.
class Functor f => Applicative fgives one way to automatically define fmap
class Functor f => Traversable fgives another way to define fmap for free
class Functor f => Comonad fgives a third way to define fmap for free
In general when you have a lattice of properties points above you in the lattice will start getting an exploding number of definitions from classes below them, leading to limited utility for any 'hiding' based mechanism as you've traded n definitions for n hiding declarations.
2.) As typeclass hierarchies become deeper with more refined notions, say, Functor, Semiapplicative, Semimonad, Pointed, Applicative, Monad (note the last 2 only have laws with no methods in the perfect world), you wind up being able to get fewer default/mutual definitions to work at any individual level of the hierarchy.
3) Product-like constructions, monad transformers, etc. still need definitions for every point in the typeclass lattice. Since almost all of my code is polymorphic in this style, it turns out I almost never get to use the instances that would be supplied by a default superclass system.
I'd say it depends how it's presented. The main selling point for adding fine grained hierarchy is that more things get a common type class. Like we could say we don't need Functors or Applicatives because most of them are Monads anyway, but still people agree that Functors are useful and needed. So I think the main objection of the average Haskeller is that introducing a new type class breaks (his) stuff. If we can find a mechanism how to avoid that, I'd say (s)he wouldn't mind (perhaps even care).
I generally favor the notion of adding default definitions for superclass methods and adding 'default instances', I just think it is necessary to point out that it doesn't help nearly as much as everyone thinks it will, when it comes to the pains induced by retroactively adding a finer grained inheritance hierarchy.
Culturally, it is a hard sell to the average Haskeller to get them to embrace a class that doesn't give them any new methods, so we wind up with an awkward culture that favors a few powerful abstractions over the full menagerie of accurate types.
-Edward
On Mon, Aug 26, 2013 at 2:18 PM, Petr Pudlák <petr.mvd@gmail.com> wrote:
One of our students is currently exploring how to extend Haskell so that splitting classes into more fine-grained hierarchy won't cause these problems:
https://groups.google.com/forum/#!topic/haskell-cafe/W1NbrikzgCQ
along the lines of
http://ghc.haskell.org/trac/ghc/wiki/DefaultSuperclassInstances
Unfortunately, it seems his message went unnoticed by Haskell community.
Best regards,
Petr Pudlak
Dne 08/26/2013 07:16 PM, Edward Kmett napsal(a):
There are several uses of Pointed as a separate beast from Applicative. In particular it comes up when we talk about "affine traversals", and would let us refine the type hierarchy of lens, so you'd think I'd be for it.
However, to move it into its own class would require literally everyone who currently has an Applicative instance to clutter their code with CPPs.
Even as the author of the Pointed class, I personally find that the benefit of the change doesn't warrant the impact of the change.
-Edward
On Mon, Aug 26, 2013 at 12:59 PM, Henning Thielemann <schlepptop@henning-thielemann.de> wrote:
There was a lot of discussion about separating "pure" from Applicative and putting it into a Pointed class. If I remember correctly, the main counter argument was that 'pure' alone does not satisfy interesting laws. There are only such laws in connection with the Applicative class.
Now, in some situations I liked to have a generalized unfoldr. I can build this from "pure" and "sequenceA" using the State monad:
unfoldr :: (Pointed t, Traversable t) => (s -> (a, s)) -> s -> t a
unfoldr = evalState . sequenceA . pure . state
One could state a law like:
traverse f (pure a) == traverse id (pure (f a))
Would this justify to move "pure" into a new Pointed class?
_______________________________________________
Libraries mailing list
Libraries@haskell.org
http://www.haskell.org/mailman/listinfo/libraries
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries