module Proarrow.Category.Instance.Free where

import Data.Kind (Type)

import Proarrow.Core (CAT, UN, Is, CategoryOf(..), Promonad(..), Profunctor(..), (:~>), dimapDefault)


infixr 4 :|

newtype FREE (g :: k -> k -> Type) = F k
type instance UN F (F k) = k

type Free :: CAT (FREE g)
data Free a b where
  FreeId :: Free (F a) (F a)
  (:|) :: g a b -> Free (F b :: FREE g) (F c) -> Free (F a :: FREE g) (F c)

class Rewrite g where
  rewriteAfterCons :: (Free :: CAT (FREE g)) :~> (Free :: CAT (FREE g))

instance Rewrite g => CategoryOf (FREE g) where
  type (~>) = Free
  type Ob a = Is F a

instance Rewrite g => Promonad (Free :: CAT (FREE g)) where
  id :: forall (a :: FREE g). Ob a => Free a a
id = Free a a
Free ('F (UN 'F a)) ('F (UN 'F a))
forall {k} {g :: k -> k -> Type} (a :: k). Free ('F a) ('F a)
FreeId
  Free b c
FreeId . :: forall (b :: FREE g) (c :: FREE g) (a :: FREE g).
Free b c -> Free a b -> Free a c
. Free a b
a = Free a b
Free a c
a
  Free b c
a . Free a b
FreeId = Free b c
Free a c
a
  Free b c
a . (g a b
g :| Free ('F b) ('F c)
b) = Free a c -> Free a c
forall {k} (g :: k -> k -> Type). Rewrite g => Free :~> Free
Free :~> Free
rewriteAfterCons (g a b
g g a b -> Free ('F b) ('F (UN 'F c)) -> Free ('F a) ('F (UN 'F c))
forall {k} (g :: k -> k -> Type) (a :: k) (b :: k) (c :: k).
g a b -> Free ('F b) ('F c) -> Free ('F a) ('F c)
:| (Free b c
Free b ('F (UN 'F c))
a Free b ('F (UN 'F c))
-> Free ('F b) b -> Free ('F b) ('F (UN 'F c))
forall {k} (p :: PRO k k) (b :: k) (c :: k) (a :: k).
Promonad p =>
p b c -> p a b -> p a c
forall (b :: FREE g) (c :: FREE g) (a :: FREE g).
Free b c -> Free a b -> Free a c
. Free ('F b) b
Free ('F b) ('F c)
b)) ((Ob b, Ob c) => Free a c) -> Free b c -> Free a c
forall {j} {k} (p :: PRO j k) (a :: j) (b :: k) r.
Profunctor p =>
((Ob a, Ob b) => r) -> p a b -> r
forall (a :: FREE g) (b :: FREE g) r.
((Ob a, Ob b) => r) -> Free a b -> r
\\ Free b c
a

instance Rewrite g => Profunctor (Free :: CAT (FREE g)) where
  dimap :: forall (c :: FREE g) (a :: FREE g) (b :: FREE g) (d :: FREE g).
(c ~> a) -> (b ~> d) -> Free a b -> Free c d
dimap = (c ~> a) -> (b ~> d) -> Free a b -> Free c d
Free c a -> Free b d -> Free a b -> Free c d
forall {k} (p :: PRO k k) (c :: k) (a :: k) (b :: k) (d :: k).
Promonad p =>
p c a -> p b d -> p a b -> p c d
dimapDefault
  (Ob a, Ob b) => r
r \\ :: forall (a :: FREE g) (b :: FREE g) r.
((Ob a, Ob b) => r) -> Free a b -> r
\\ Free a b
FreeId = r
(Ob a, Ob b) => r
r
  (Ob a, Ob b) => r
r \\ g a b
_ :| Free ('F b) ('F c)
_ = r
(Ob a, Ob b) => r
r