packages feed

proarrow-0.1.0.0: src/Proarrow/Profunctor/Instance/Fold.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

-- | The left-fold profunctor (after @Data.Fold.M@ from the @folds@ package): a @'Fold' a b@ is a monoid
-- @m@ together with arrows @a ~> m@ and @m ~> b@.
module Proarrow.Profunctor.Instance.Fold where

import Data.Kind (Type)
import Prelude qualified as P

import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), SymMonoidal, leftUnitorInvWith, swapInner)
import Proarrow.Category.Monoidal.Action (CoprodAction, ProdAction)
import Proarrow.Category.Monoidal.Applicative (Applicative (..))
import Proarrow.Category.Monoidal.Cartesian (BiCCC, Cartesian, distLProd, distRProd)
import Proarrow.Category.Monoidal.Strength (Costrong (..), Strong (..))
import Proarrow.Colimit.BinaryCoproduct (COPROD (..), HasBinaryCoproducts (..), right)
import Proarrow.Core (CategoryOf (..), Profunctor (..), Promonad (..), obj, type (+->))
import Proarrow.Functor (map)
import Proarrow.Limit.BinaryProduct (HasBinaryProducts (..), PROD (..))
import Proarrow.Monoid (Monoid (..))
import Proarrow.Profunctor.Corepresentable (Corepresentable (..))
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Promonad (Procomonad (..))

-- | A left fold from @a@ to @b@: an internal monoid @m@ with a step arrow @a '~>' m@ and an
-- extractor @m '~>' b@.
data Fold a b where
  Fold :: (Ob m) => (m ~> b) -> (a ~> m) -> (m ** m ~> m) -> (Unit ~> m) -> Fold a b

instance (CategoryOf k) => Profunctor (Fold :: k +-> k) where
  dimap f g (Fold k h m z) = Fold (g . k) (h . f) m z
  r \\ Fold f g _ _ = r \\ f \\ g

instance (CategoryOf k) => Procomonad (Fold :: k +-> k) where
  proextract (Fold f g _ _) = f . g
  produplicate (Fold f g m z) = Fold id g m z :.: Fold f id m z

instance (SymMonoidal k) => MonoidalProfunctor (Fold :: k +-> k) where
  one = Fold id id leftUnitor id
  Fold @m f g m z ** Fold @n f' g' m' z' =
    withOb2 @k @m @n P.$
      Fold (f ** f') (g ** g') ((m ** m') . swapInner @m @n @m @n) ((z ** z') . leftUnitorInv)

instance (BiCCC k) => Strong CoprodAction (Fold :: k +-> k) where
  act @(COPR a) (Fold @m k h m z) = withObCoprod @k @a @m P.$ Fold (obj @a +++ k) (right @a h) (step m) (rgt @_ @a @m . z)
    where
      step :: (Ob m, Ob a, Ob (a || m)) => (m && m) ~> m -> (a || m) && (a || m) ~> (a || m)
      step mult = (lft @k @a @m . fst @k @a @(a || m) ||| (snd @k @m @a +++ mult) . distLProd @m @a @m) . distRProd @a @m @(a || m)

instance (Cartesian k) => Costrong ProdAction (Fold :: k +-> k) where
  coact @(PR a) @_ @y (Fold f g m z) = Fold (snd @k @a @y . f) (g . leftUnitorInvWith (fst @k @a @y . f . z)) m z

trav :: (Applicative f) => Fold a b -> Fold (f a) (f b)
trav (Fold @m k h m z) = Fold (map k) (map h) (liftA2 @_ @m @m m) (pure z)

instance Corepresentable (Fold :: Type +-> Type) where
  type Fold %% a = [a]
  cotabulate f = Fold f (: []) mappend mempty
  coindex (Fold f g m z) xs = f (go xs)
    where
      go [] = z ()
      go (x : xs') = m (g x, go xs')
  corepMap = map