well-typed / optics

Optics as an abstract interface
375 stars 24 forks source link

Strictify traversals? #474

Open treeowl opened 1 year ago

treeowl commented 1 year ago

I'm currently working on a PR for lens that adds

strictly :: (Profunctor p, Profunctor q, Functor f) => Optical p q (BoxT f) s t a b -> Optical p q f s t a b
strictly l f = rmap (fmap getSolo .# runBoxT) $ l (rmap (BoxT #. fmap (Solo $!)) f)

where BoxT is the following applicative transformer:

newtype BoxT f a = BoxT { runBoxT :: f (Solo a) }
  deriving Functor
instance Apply f => Apply (BoxT f) where
  liftF2 f (BoxT m) (BoxT n) = BoxT (liftF2 (liftA2 f) m n)
instance Applicative f => Applicative (BoxT f) where
  pure = BoxT . fmap Solo
  liftA2 f (BoxT m) (BoxT n) = BoxT (liftA2 (liftA2 f) m n)

-- The Contravariant instance probably isn't really useful (strictifying
-- a getter or fold doesn't change anything) but it at least *seems*
-- harmless.
instance Contravariant f => Contravariant (BoxT f) where
  contramap f (BoxT m) = BoxT (contramap (fmap f))

-- BoxT intentionally does *not* have a Settable instance,
-- because it's impossible to strictify things like `mapped` that
-- are really just setters.

I figured you might be interested in doing something similar here.