ekmett / bifunctors

Haskell 98 bifunctors, bifoldables and bitraversables
Other
57 stars 42 forks source link

Add a Backwards type #95

Closed treeowl closed 3 years ago

treeowl commented 3 years ago

Biapplicative instances are reversable just like Applicative ones. Add a Backwards type to demonstrate that.

treeowl commented 3 years ago

I don't think it should have its own module, and I think Backwards should move to Control.Applicative, but then again this package seems to like a separate module for each type, so I guess that's okay. Your other remarks are totally uncontroversial, and I'll definitely make those changes

treeowl commented 3 years ago

One minor concern: not very many types are both Biapplicative and Applicative. Should Backwards have at Applicative instance at all? On the other hand, it's possible to imagine it as a (conceptually infinite) family

data family Backwards :: k
newtype instance Backwards a = Backwards0 { forwards0 :: a }
newtype instance Backwards f a = Backwards1 { forwards1 :: f a } 
newtype instance Backwards f a b = Backwards2 { forwards2 :: f a b }
newtype instance Backwards f a b c = Backwards3 { forwards3 :: f a b c }
...

for turning around constructors of any arity that may be required and providing the appropriate Monoid, Applicative, Biapplicative, etc., instances for all possible arities. So ... I think it's probably okay to think of Data.Biapplicative.Backwards not as "turning around Biapplicative" but rather as "turning around NApplicative for N <= 2".

treeowl commented 3 years ago

Of course, my last comment raises an interesting question: should we actually offer that data family instead? I kind of like it. Almost all the instances can be produced using DerivingVia, which is kind of cool.

treeowl commented 3 years ago

Oh, and even if we don't do that, should we add a Dual Monoid instance for Backwards?

treeowl commented 3 years ago

@RyanGlScott Do you have any idea why the older GHCs are balking at this? The only workaround I've found so far is to make every single derived instance standalone, which is really awful.

RyanGlScott commented 3 years ago

I think it's probably okay to think of Data.Biapplicative.Backwards not as "turning around Biapplicative" but rather as "turning around NApplicative for N <= 2".

I agree.

Of course, my last comment raises an interesting question: should we actually offer that data family instead?

I don't have a strong opinion on this, but if we do go that route, I think we should do it in a separate commit. There are other data types in bifunctors that, conceptually, could also be made into data families (e.g., Fix, Biap, and possibly others).

Do you have any idea why the older GHCs are balking at this?

This is likely due to an old GHC bug of some sort, but I'm hard-pressed to remember which one it is. Unfortunately, we may just have to live with standalone deriving if we pursue this design.

treeowl commented 3 years ago

@RyanGlScott, all right. I pulled the data family stuff out of this PR; we can consider it elsewhere.

treeowl commented 3 years ago

Even if I can find a way to make the StandaloneDeriving bearable (at least temporarily), I think some Microsurgery will be required to produce the Generic and Generic1 instances. I didn't check if that's an issue in 8.8, or only in 8.6, but 8.6 just can't derive those for Backwards at all. I don't know if it's an issue with polykinded data families specifically, data families in general, or what.

treeowl commented 3 years ago

Almost done, but I want custom Show and Read instances to avoid the record syntax noise.

treeowl commented 3 years ago

I've had second thoughts about Backwards. Might be better to go with separate types for reversing n-Applicatives for each n, while perhaps making each a data family for constructors of different arity. It's just not obvious the way Reverse is.

RyanGlScott commented 3 years ago

I've had second thoughts about Backwards. Might be better to go with separate types for reversing n-Applicatives for each n, while perhaps making each a data family for constructors of different arity.

I'm fine with whichever route you end up choosing, provided that the final design is clearly explained in the Haddocks.

treeowl commented 3 years ago

@RyanGlScott , I think that covers everything. I also added a slew of derived instances. Note: I think the Show and Read approaches taken here should be applied to things like Tannen and Biff as well, but that's for a different PR.