adjunctions icon indicating copy to clipboard operation
adjunctions copied to clipboard

New Representable methods feel cramped

Open treeowl opened this issue 4 years ago • 5 comments

We now have

  collect1 :: Functor1 w => (forall x. g x -> f x) -> w g -> f (w Identity)

We can generalize this immediately:

  coll2 :: (Applicative h, Functor1 w) => (forall x. g x -> f x) -> w g -> f (w h)
  coll2 f = cotraverse1 (map1 (pure . runIdentity)) . map1 f

I don't know if it's possible to weaken the Applicative constraint.

treeowl avatar Sep 04 '19 21:09 treeowl

Ah, like this:

  coll1
    :: Functor1 w
    => (forall x. x -> h x) -> (forall x. g x -> f x) -> w g -> f (w h)

This can avoid an extra fmap (map1 (p . runIdentity)) at the end, compared to the current collect1.

treeowl avatar Sep 04 '19 21:09 treeowl

No no no, that's not the way to do it either. Here we go:

  collection
     :: Functor1 w
     => (forall x. g x -> f (h x))
     -> w g -> f (w h)
  collection f =
     tabulate
     . (\w i -> map1 (flip index i . getCompose) w)
     . map1 (Compose #. f)

Isn't that more satisfying?

treeowl avatar Sep 04 '19 22:09 treeowl

cotraverse1 then becomes

  cotraverse1' :: Functor1 w => (w h -> a) -> w (Compose f h) -> f a

which is unsatisfying in just the right way. Finally, we get to the most powerful method,

  cotraverseMap1' ::
       Functor1 w => (w h -> a) -> (forall x. g x -> f (h x)) -> w g -> f a
  cotraverseMap1' f g = cotraverse1' f . map1 (Compose . g)

Lovely, eh?

treeowl avatar Sep 04 '19 22:09 treeowl

Isn't that more satisfying?

The point of the new methods is to avoid index since it's O(n) for instances like Stream.

cotraverse1 then becomes

@sjoerdvisscher also suggested that version on twitter. As I replied there, I had that version at one point but found that the Identity version is more convenient. The compose version should also be added though, and could replace a bit of code duplication in the Cofree and (:.:) instances. I can make a PR for this and a couple other additions I've had in mind.

I don't think the compose version needs to be a method though; it can just be a derived function.

aaronvargo avatar Sep 04 '19 23:09 aaronvargo

No comment on that particular practicality, but I've run into another rather annoying one: the cotraverse1 and distribute1 methods are incompatible with GeneralizedNewtypeDeriving. Ouch! This isn't really surprising, since distribute is as well. But that makes me very tempted to say we should omit those and just have collect1 and cotraverseMap1.

treeowl avatar Sep 05 '19 01:09 treeowl