Open langston-barrett opened 5 years ago
They are indeed the same classes; and I just noticed that I could end up introducing equivalents of Data.Parameterized.{FunctorFC. TraversableFC}
as well (see the proposed Functor2B
and Traversable2B
in https://github.com/jcpetruzza/barbies/issues/13#issuecomment-486418604).
I agree that it could be preferable to reduce duplication, if possible. Did you have anything in mind? From my point of view, of course, the simplest thing would be for parameterized-utils
to re-export the definitions from barbies
. Because of the slightly different naming convention this is a change that would induce a lot of breakage on users of parameterized-utils
, so I'd understand if you this were not your favourite plan :slightly_smiling_face:.
But because of the default instances in FunctorB
and TraversableB
, I cannot just replace FunctorB
with FunctorF
, etc., so the alternative would be to move all the generic definitions to parameterized-utils
and reexport FunctorF
from barbies
. Apart from the breakage due to naming, there'd be the issue of dependencies: currently barbies
depends only on bifunctors
(and since most was moved to base
in ghc 8, I'm planning to drop that dependency as well). Depending on parameterized-utils
would bring along lens
, etc. and I'd rather keep the library lightweight.
@jcpetruzza Thanks for the thoughtful reply! I guess I didn't have anything in mind, for the reasons you outline :smile:
The default instances look quite helpful, we do something somewhat similar for GADTs with template haskell.
It's worth noting that at least the Functor(B|F)
class seems broadly appealing, it's defined in at least one more package: compdata (as HFunctor
), and discussed in at least one blog post
I would think that the most generally useful solution would probably be to create a small package (e.g. higher-order-functors
) and have both parameterized-utils
and barbie
depend on it. That package could contain both the default instances of barbies
and some of the GADT TH stuff from parameterized-utils
.
Thanks for the pointers! I think that HFunctor
in compdata is actually a different beast, but the blog post you mention links to other packages that do define exactly the same notion, most notably rank2classes and conkin.
Now, all of conkin
, rank2classes
and barbies
are a possible version of the proposed higher-order-functors
package: they begin by defining a "higher-order functor" type-class and then build a hierarchy of sub-classes from there (Traversable
, Applicative
, etc). They are exploring the design space in various ways, making different trade-offs... and they agree only on Functor
! (e.g., rank2classes
and barbies
agree on Traversable
, but the latter has no Foldable
class; rank2classes
and conkin
agree on Applicative
, but the latter has no Apply
, etc.).
So, let's say we were to start higher-order-functors
package with Functor
only, as you propose. Some things to keep in mind:
Functor
is not enough, people will end up depending on one package or the other for the rest of the hierarchy and I suspect that then we'd be more or less back to where we are now?@jcpetruzza I just noticed that there's some conceptual duplication between FunctorF
and FunctorFC
in the first place, see issue 41 on parameterized-utils.
So..
all licensed under BSD (2/3 clause).
I am to blame for the third in that list.
rank2classes came first, but for some reason now has a strange lower bound and no upper bound on base, and its repo is shared with some other packages.. but it does have the most comprehensive collection of rank2 classes. And the most sensible name for this kind of package, to be honest.
For posterity, here are even more instances of higher-order functors
Not only are the Functor(B|F)
classes duplicated, we also have duplication between Functor(T|FC)
. For the latter, there's heavy duplication with https://hackage.haskell.org/package/sop-core-0.5.0.1/docs/Data-SOP-Classes.html as well.
@jcpetruzza @langston-barrett I'd be super interested in working on factoring out a common core here, but as @jcpetruzza mentioned, a high level plan for something that would work in both libraries is needed.
But because of the default instances in
FunctorB
andTraversableB
, I cannot just replaceFunctorB
withFunctorF
, etc., so the alternative would be to move all the generic definitions to parameterized-utils and reexportFunctorF
from barbies.
Another alternative would be to drop the defaults, create a newtype like GBarbie :: (k -> Type) -> Type
, and attach all the generically derived instances for <shared-higher-order-functor-classes-library>
to that. The user for their part can derive instances for their HKDs via
that newtype. Would that approach make any sense? It would of course be a tremendous breakage, but there's ways to mitigate the scope of the problem with naming tricks.
@masaeedu Having a newtype wrapper to use with deriving-via would be nice, independently of the larger issue. I think I ran into some issues when I tried it some time ago, but I don't remember the details. If you make it work, that'd be great :)
@jcpetruzza Might it have been the TraversableB
typeclass? Traversable
has issues being derived via a newtype, and I would anticipate so does TraversableB
. That said, if you're ok with tweaking the definition of TraversableB
to make it weaker (as seen in the linked answer), we can do that and add a newtype wrapper via which you can get all the relevant instances.
It looks like this library has some typeclasses that are also defined in
parameterized-utils
. I wonder if we could reduce the duplication of effort.In particular:
FunctorB <-> Data.Parameterized.TraversableF.FunctorF
TraversableB <-> Data.Parameterized.TraversableF.TraversableF