what’s the profunctor representation of wither?

Chris here; here’s my swing at the profunctor optics representation:

Here’s the profunctor class:

import Data.Profunctor
import Data.Profunctor.Traversing
import Control.Applicative

class (Traversing p) => Withering p where
  cull :: (forall f. Alternative f => (a -> f b) -> (s -> f t)) -> p a b -> p s t

instance Alternative f => Withering (Star f) where
  cull f (Star amb) = Star (f amb)

instance Monoid m => Withering (Forget m) where
  cull f (Forget h) = Forget (getAnnihilation . f (AltConst . Just . h))
    where
      getAnnihilation (AltConst Nothing) = mempty
      getAnnihilation (AltConst (Just m)) = m

newtype AltConst a b = AltConst (Maybe a)
  deriving stock (Eq, Ord, Show, Functor)

instance Monoid a => Applicative (AltConst a) where
  pure _ = (AltConst (Just mempty))
  (AltConst Nothing) <*> _ = (AltConst Nothing)
  _ <*> (AltConst Nothing) = (AltConst Nothing)
  (AltConst (Just a)) <*> (AltConst (Just b)) = AltConst (Just (a <> b))

instance (Semigroup a) => Semigroup (AltConst a x) where
  (AltConst Nothing) <> _ = (AltConst Nothing)
  _ <> (AltConst Nothing) = (AltConst Nothing)
  (AltConst (Just a)) <> (AltConst (Just b)) = AltConst (Just (a <> b))

instance (Monoid a) => Monoid (AltConst a x) where
  mempty = (AltConst (Just mempty))

instance Monoid m => Alternative (AltConst m) where
  empty = (AltConst Nothing)
  (AltConst Nothing) <|> a = a
  a <|> (AltConst Nothing) = a
  (AltConst (Just a)) <|> (AltConst (Just b)) = (AltConst (Just (a <> b)))

If you’re interested in some of the optics that arise, I’ve implemented a few of those here:

It’s definitely possible there are other interpretations or perhaps some simpler representation, but at the moment this seems to do the trick. If anyone else has other ideas I’d love to see them!

Happy to chat about it more if you have any other questions!

CLICK HERE to find out more related problems solutions.

Leave a Comment

Your email address will not be published.

Scroll to Top