ekmett / lens

Lenses, Folds, and Traversals - Join us on web.libera.chat #haskell-lens
http://lens.github.io/
Other
2.03k stars 273 forks source link

Add a class for certain indexed efficiencies #790

Open treeowl opened 6 years ago

treeowl commented 6 years ago

As discussed in comments on #789, it can be pretty hard to avoid space leaks and such when capturing indexed traversals. Here's one idea. There are a few ways to wiggle it, but you should get the idea.

class (Profunctor p, Functor f, f ~ Fun p) => Cosieve p f where
  type Fun p :: * -> *
  cosieve :: p a b -> f a -> b

-- The only reason to separate this from Cosieve is to keep the Cosieve dictionary
-- tiny. I don't know if that matters.
class Cosieve p f => Foo p f where
  type Index p :: *
  type Index p = Fun p ()

  cosieve' :: p a b -> Index p -> a -> b
  default cosieve' :: (Index p ~ Fun p ()) => p a b -> Index p -> a -> b
  cosieve' pab i a = cosieve pab (a <$ i)

class (Cosieve p (Corep p), Costrong p) => Corepresentable p where
  type Corep p :: * -> *
  type Corep p = Fun p

  cotabulate :: (Corep p d -> c) -> p d c

class (Category p, Corepresentable p, Foo p (Corep p)) => Bar p where
  cotabulate' :: forall d c. (Index p -> d -> c) -> p d c
  default cotabulate' :: forall d c. Index p ~ Corep p () => (Index p -> d -> c) -> p d c
  cotabulate' f = cotabulate (\r -> f (() <$ r) (cosieve (id :: p a a) r))

  cotabulate_ :: forall d c. (d -> c) -> p d c
  cotabulate_ f = cotabulate' (\ _i x -> f x)

The idea is that the non-(->) case in conjoined can use the methods that keep indices and values separate, which will be good for Indexed.

treeowl commented 6 years ago

An alternative would be dump all those methods into Conjoined.