tweag / linear-base

Standard library for linear types in Haskell.
MIT License
335 stars 37 forks source link

Design: Consistent & Non-Abitrary Module Structure #274

Closed Divesh-Otwani closed 3 years ago

Divesh-Otwani commented 3 years ago

The internal module structure has some major (not completely disjoint) problems:

I propose the following system and subsequent changes:

I recognize this system is abstract but hopefully there are enough examples to give a clear enough idea of my proposed solution.

aspiwack commented 3 years ago

I don't agree with all of this.

Divesh-Otwani commented 3 years ago

I don't agree with all of this.

Correct me if I'm wrong, but I think this means what you don't explicitly disagree with you are neutral or in support of.

Internal module need to be named Internal one way or another (it doesn't need to be the final item in the module path, but it needs to be there) this does signal: this is not public interface, it exists purely for internal, technical reason, use at your own risk: it won't be considered in backwards compatibility. It's a convention that we can't do without in current Haskell.

I wasn't advocating for removing the Internal from the path of the name; just that naming the file Internal.hs communicates nothing unless we have a convention of what these Internal.hs files mean and what they stand for. And my main point is "internal modules should have clear boundaries" usually because they are centered around a concept.

It may be worth it making smaller internal modules, though, since it would increase build parallelism, and conceivably makes the imports more predictable.

I would emphasize that it's more than predictable: it makes the use of these readable, sustainable as the project grows, easier to read, etc.

I think that you are advocating for moving all the code into such internal modules and only use public module to re-export code from such internal modules: why not. I rather like the idea even.

That might be a consequence of what I"m saying but what I want is the opposite of my three complaints: non-arbitrariness, cohesion and consistency.

Data.Functor is nice: everything in there are functors. That's what I want this module to be named. But Control.Monad should become Control.Functor. If you need an internal name for “just the Functor type class” , you can use Data.Functor.Internal.Functor. A bit redundant, but very regular.

I don't think a new user will find it intuitive to see Applicative Functors in Data.Functor. If we are going to depart from the way base makes things in a lot of self-contained modules then we can't use the same names. We should call it Data.Functorial.Linear or something. Otherwise this will just be another strange thing a new user has to learn to use linear-base and I'd like as little of that as possible. More fundamentally, linear-base is not about making corrections to things we don't like in base -- we should do as little as possible of that and focus as much as possible on the linear part.

Likewise, it's Symmetric Monoidal products are in the right place in Data.Bifunctor.Linear, I don't know why we would want to change it. (again, making a dedicated internal module for it is ok)

Exactly the point I'm making about Data.Functor applies here. It just makes it harder for a new user who can't read the minds of the writers of linear-base.

  We do as we did with functors to `Data.Profunctor.*`     

I don't know what this means.

This means we put Data.Profunctor.{Profunctor, Wandering, Exchange} each in it's own internal file and have a Data.Kleisli.Linear. However, as I'm writing this I think I'll defer this to when I take a look at optics.

     We make similar changes wherever else there are internal modules or ought to be because there are
      too many ideas in a file that aren't unified under a clear purpose or concept to the module.

I don't know what this means either.

If there isn't a clear boundary or concept that defines an internal module then it should be broken up into more internal modules each of which have clear boundaries and are ideally centered around a concept.

aspiwack commented 3 years ago

I don't think a new user will find it intuitive to see Applicative Functors in Data.Functor. If we are going to depart from the way base makes things in a lot of self-contained modules then we can't use the same names. We should call it Data.Functorial.Linear or something. Otherwise this will just be another strange thing a new user has to learn to use linear-base and I'd like as little of that as possible.

This discussion is not going to be resolved by arguing. So let me just make this a decision: Functor stays.

More fundamentally, linear-base is not about making corrections to things we don't like in base -- we should do as little as possible of that and focus as much as possible on the linear part.

This is not true. There are plenty of corrections, in linear-base, to things in base that I believe haven't stood the test of time. Not everything, one has to choose their combat. But it's not the goal to make a strict base look-alike with different arrows.

Divesh-Otwani commented 3 years ago

Okay, so the things that remain are minimal enough that I think this issue can be closed. The module organization that I think could be made just a bit cleaner is:

Suffice it to say, all the big things are taken care of.

Also, as an "Author's note": some of the wording above is a bit too emotional and not as grounded it could have been. Let's just say 2020 was a rough year.