tomjaguarpaw / product-profunctors

Other
19 stars 14 forks source link

Needed parts for one-liner #27

Closed sjoerdvisscher closed 7 years ago

tomjaguarpaw commented 7 years ago

Thanks!

Can you explain the meaning of end? If it's supposed to be the identity of +++! shouldn't it be end :: p Void a?

tomjaguarpaw commented 7 years ago

To be more precise. p Void a is equivalant to p Void Void but p a a is not, so I suspect we don't actually want p a a.

sjoerdvisscher commented 7 years ago

I actually need p a a to deal with constants that don't need to be touched. It's just a coincidence that zero can be implemented. I really just need it as "identity" but Identity and id are already used so often, and end isn't and still technically a correct term.

Oh, I now realise that the implementation can just be zero = end and probably is not worth including. In my code I had zero :: p (V1 a) (V1 b).

tomjaguarpaw commented 7 years ago

Hmm, so perhaps you actually want Strong?

tomjaguarpaw commented 7 years ago

https://hackage.haskell.org/package/profunctors-5.2/docs/Data-Profunctor-Strong.html

tomjaguarpaw commented 7 years ago

I'm very suspicious of p a a and I suspect that it's a coincidence that it works and you actually want something else.

tomjaguarpaw commented 7 years ago

Actually I'm not suspicious of it. It's a perfectly good class but it is strictly less general (in combination with ProductProfunctor) than Strong.

Is Strong sufficient for your needs?

sjoerdvisscher commented 7 years ago

This is the only place where I use it: https://github.com/sjoerdvisscher/one-liner/blob/master/src/Generics/OneLiner/Internal.hs#L110

So what I need is p (K1 i c a) (K1 i c b). K1 is from GHC.Generics and defined as

newtype K1 (i :: *) c (p :: *) = K1 { unK1 :: c }

so after dimap unK1 K1 I just need a p c c. I don't see how Strong would help me here.

tomjaguarpaw commented 7 years ago

At the very least you can get p c c from p () () and first' :: p a b -> p (a, c) (b, c).

I wonder if ProductProfunctor p, Strong p is actually equivalent to ProductProfunctor p, ProfunctorEnd p.

sjoerdvisscher commented 7 years ago

Ah, indeed! It looks like they are.

first' p = p ***! end
second' p = end **! p

And as you said you can get end from empty and first'. Scratch that class then.

sjoerdvisscher commented 7 years ago

The only ProfunctorEnd instance that isn't Strong is Joker. With the above the instance would become

instance Alternative f => Strong (Joker f) where
  first' (Joker fb) = Joker $ liftA2 (,) fb Alternative.empty

But I could work around this missing instance. Using Alternative just for its empty was ugly anyway.

tomjaguarpaw commented 7 years ago

The Product/SumProfunctor instances are uncontroversial so I merged them anyway.

Having thought about it some more I believe that ProfunctorEnd is a meaningful class so let me know if you want me to add that too.

sjoerdvisscher commented 7 years ago

With ProductProfunctor being Profunctor+Applicative and ProfunctorEnd being Strong+Applicative there only has to be a nice replacement for SumProfunctor and I would not need this whole package...

sjoerdvisscher commented 7 years ago

SumProfunctor p is the same as Decidable (Flip p) a.

But there's actually good reason to use this package after all! There can be different instances of Applicative (p a), depending on if you're seeing p as a Profunctor or as a Bifunctor. For example the instance for Clown f a would need Divisible f or Alternative f respectively.