Skip to content

Instantly share code, notes, and snippets.

@sjoerdvisscher
Last active June 12, 2022 11:48
Show Gist options
  • Save sjoerdvisscher/2905377ec9118570d35486159fc3b6e4 to your computer and use it in GitHub Desktop.
Save sjoerdvisscher/2905377ec9118570d35486159fc3b6e4 to your computer and use it in GitHub Desktop.
Implementation of the Poly category in Haskell
{-# LANGUAGE GHC2021, PatternSynonyms, LambdaCase, DataKinds, PolyKinds, TypeFamilies, NoStarIsType, UndecidableInstances, UndecidableSuperClasses, AllowAmbiguousTypes, DefaultSignatures #-}
import Data.Functor (void)
import Data.Bifunctor (bimap)
import Data.Kind (Type, Constraint)
import Data.Void
-- from fin
import Data.Fin (Fin(..))
import qualified Data.Fin as Fin
import Data.Type.Nat
prev :: forall n. SNat ('S n) -> SNat n
prev SS = snat
type PolyKind = [(Type, Type)]
data Prf (p :: PolyKind) where
PrfNil :: Prf '[]
PrfCons :: Prf p -> Prf ('(a, b) ': p)
class IsP (p :: PolyKind) where
prf :: Prf p
instance IsP '[] where
prf = PrfNil
instance (ab ~ '(a, b), IsP p) => IsP (ab ': p) where
prf = PrfCons prf
infixr 0 //
(//) :: Prf p -> (IsP p => r) -> r
PrfNil // r = r
PrfCons p // r = p // r
infixr 0 ///
(///) :: (q -> Prf p) -> (IsP p => q -> r) -> q -> r
f /// g = \q -> f q // g q
type family AllA (ca :: Type -> Constraint) (p :: PolyKind) :: Constraint where
AllA ca '[] = ()
AllA ca ('(a, b) ': p) = (ca a, AllA ca p)
type family AllB (cb :: Type -> Constraint) (p :: PolyKind) :: Constraint where
AllB cb '[] = ()
AllB cb ('(a, b) ': p) = (cb b, AllB cb p)
type All ca cb p = (AllA ca p, AllB cb p)
-- | Polynomial functors as a sum of monomials @a * y ^ b@
data PolyF (p :: PolyKind) y where
Y :: IsP p => a -> (b -> y) -> PolyF ('(a, b) ': p) y
N :: PolyF p y -> PolyF ('(a, b) ': p) y
instance Functor (PolyF p) where
fmap f (Y a by) = Y a (f . by)
fmap f (N p) = N (fmap f p)
-- | Natural transformations between polynomial functors
type p ~> q = forall y. PolyF p y -> PolyF q y
-- | Concrete representation of natural transformations between polynomial functors.
-- For each monomial @a * y ^ b@ we have for each @a@ a @q@ polynomial full of @b@s which specify which @y@ was used from the monomial.
data Poly (p :: PolyKind) (q :: PolyKind) where
PNil :: IsP q => Poly '[] q
P :: (a -> PolyF q b) -> Poly p q -> Poly ('(a, b) ': p) q
-- | @Y@ in the shape of the argument to @P@
py :: IsP p => (b -> y) -> a -> PolyF ('(a, b) ': p) y
py = flip Y
fromMonoF :: PolyF (Mono a b) y -> (a, b -> y)
fromMonoF (Y a by) = (a, by)
fromMonoF (N p) = case p of {}
-- Conversions between the two representations.
fromPoly :: Poly p q -> p ~> q
fromPoly PNil p = case p of {}
fromPoly (P qs _) (Y a ys) = fmap ys (qs a)
fromPoly (P _ pq) (N p) = fromPoly pq p
toPoly :: forall p q. (IsP p, IsP q) => (p ~> q) -> Poly p q
toPoly f = case prf @p of
PrfNil -> PNil
PrfCons p -> p // P (f . py id) (toPoly (f . N))
prfF :: PolyF p y -> Prf p
prfF (Y _ _) = prf
prfF (N p) = PrfCons (prfF p)
prfP :: Poly p q -> Prf p
prfP PNil = PrfNil
prfP (P _ pq) = PrfCons (prfP pq)
prfQ :: Poly p q -> Prf q
prfQ PNil = prf
prfQ (P _ pq) = prfQ pq
prfTail :: Prf ('(a, b) : p) -> Prf p
prfTail (PrfCons p) = p
mapP :: IsP r => (q ~> r) -> Poly p q -> Poly p r
mapP _ PNil = PNil
mapP f (P qs pq) = P (f . qs) (mapP f pq)
liftQ :: Poly p q -> Poly p ('(a, b) ': q)
liftQ PNil = PNil
liftQ (P qs pq) = P (N . qs) (liftQ pq)
-- Poly is a category
idP :: IsP p => Poly p p
idP = toPoly id
compP :: Poly q r -> Poly p q -> Poly p r
compP q = prfQ q // mapP (fromPoly q)
type Zero = '[]
type Mono a b = '[ '(a, b) ]
type Duo a b c d = '[ '(a, b), '(c, d) ]
type I = Mono () Void
type Y = Mono () ()
mkY :: y -> PolyF Y y
mkY y = Y () (const y)
-- type List = ListN 'Z
-- type ListN n = '((), Fin n) ': ListN ('S n)
-- Some adjunctions
-- p(1) |- Ay (x = ()) and p(0) |- A (x = Void)
adj1 :: IsP p => (a -> PolyF p x) -> Poly (Mono a x) p
adj1 f = P f PNil
-- A |- p(1)
adj2 :: IsP p => (PolyF p () -> a) -> Poly p (Mono a Void)
adj2 f = toPoly (\p1 -> Y (f $ void p1) absurd)
data Gamma (p :: PolyKind) where
GNil :: Gamma '[]
G :: b -> Gamma p -> Gamma ('(a, b) ': p)
-- y^A |- Gamma(p)
adj3 :: forall p a. IsP p => Poly (Mono () a) p -> (Gamma p -> a)
adj3 (P f PNil) g = loop (f ()) g where
loop :: PolyF q a -> (Gamma q -> a)
loop (Y _ ba) (G b _) = ba b
loop (N p) (G _ g') = loop p g'
-- Coproducts
type family (++) (p :: PolyKind) (q :: PolyKind) :: PolyKind where
'[] ++ q = q
('(a, b) ': p) ++ q = '(a, b) ': (p ++ q)
coprodPrf :: Prf p -> Prf q -> Prf (p ++ q)
coprodPrf PrfNil q = q
coprodPrf (PrfCons p) q = PrfCons (coprodPrf p q)
inj1P :: Prf p -> Prf q -> Poly p (p ++ q)
inj1P PrfNil q = q // PNil
inj1P (PrfCons p) q = (prfQ /// P (py id) . liftQ) (inj1P p q)
inj2P :: Prf p -> Prf q -> Poly q (p ++ q)
inj2P PrfNil q = q // idP
inj2P (PrfCons p) q = p // liftQ (inj2P p q)
(|||) :: Poly p r -> Poly q r -> Poly (p ++ q) r
PNil ||| qr = qr
P r pr ||| qr = P r (pr ||| qr)
coprodSwap :: Prf p -> Prf q -> Poly (p ++ q) (q ++ p)
coprodSwap p q = inj2P q p ||| inj1P q p
coprodBimap :: Poly p0 q0 -> Poly p1 q1 -> Poly (p0 ++ p1) (q0 ++ q1)
coprodBimap pq0 pq1 = (inj1P q0 q1 `compP` pq0) ||| (inj2P q0 q1 `compP` pq1)
where
q0 = prfQ pq0
q1 = prfQ pq1
inj1 :: forall p q. (IsP p, IsP q) => Poly p (p ++ q)
inj1 = inj1P @p @q prf prf
inj2 :: forall p q. (IsP p, IsP q) => Poly q (p ++ q)
inj2 = inj2P @p @q prf prf
inj1F :: Prf p -> Prf q -> p ~> (p ++ q)
inj1F p q = fromPoly (inj1P p q)
inj2F :: Prf p -> Prf q -> q ~> (p ++ q)
inj2F p q = fromPoly (inj2P p q)
coprodF :: Prf p -> (PolyF p y -> r) -> (PolyF q y -> r) -> PolyF (p ++ q) y -> r
coprodF PrfNil _ qr r = qr r
coprodF (PrfCons p) pr _ (Y a by) = p // pr (Y a by)
coprodF (PrfCons p) pr qr (N pq) = coprodF p (pr . N) qr pq
-- Apply Hask functors to the parameters of a polynomial
type family ApplyA (f :: Type -> Type) (q :: PolyKind) :: PolyKind where
ApplyA f '[] = '[]
ApplyA f ('(qa, qb) ': q) = '(f qa, qb) ': ApplyA f q
applyAPrf :: forall f q. Prf q -> Prf (ApplyA f q)
applyAPrf PrfNil = PrfNil
applyAPrf (PrfCons q) = PrfCons (applyAPrf @f q)
applyAP :: forall f p y. (forall a. a -> f a) -> PolyF p y -> PolyF (ApplyA f p) y
applyAP f (Y pa pby) = prfTail (applyAPrf @f (prf @p)) // Y (f pa) pby
applyAP f (N p) = N (applyAP f p)
type family ApplyB (f :: Type -> Type) (q :: PolyKind) :: PolyKind where
ApplyB f '[] = '[]
ApplyB f ('(qa, qb) ': q) = '(qa, f qb) ': ApplyB f q
applyBPrf :: forall f q. Prf q -> Prf (ApplyB f q)
applyBPrf PrfNil = PrfNil
applyBPrf (PrfCons q) = PrfCons (applyBPrf @f q)
applyBP :: forall f p y0 y1. (forall b. (b -> y0) -> f b -> y1) -> PolyF p y0 -> PolyF (ApplyB f p) y1
applyBP f (Y pa pby) = prfTail (applyBPrf @f (prf @p)) // Y pa (f pby)
applyBP f (N p) = N (applyBP f p)
type Apply f g q = ApplyA f (ApplyB g q)
-- Multiply with a monomial
-- a * y^b * q
type family (.*) (ab :: (Type, Type)) (q :: PolyKind) :: PolyKind where
'(a, b) .* q = Apply ((,) a) (Either b) q
scaleAPrf :: forall a b p q. Prf ('(a, b) ': p) -> Prf q -> Prf (ApplyA ((,) a) q)
scaleAPrf _ = applyAPrf @((,) a)
scalePrf :: forall a b p q. Prf ('(a, b) ': p) -> Prf q -> Prf ('(a, b) .* q)
scalePrf p q = scaleAPrf p (applyBPrf @(Either b) q)
scaleP :: forall a b p y. a -> (b -> y) -> PolyF p y -> PolyF ('(a, b) .* p) y
scaleP a by = scaleAP a . applyBP (either by)
scaleAP :: forall a p y. a -> PolyF p y -> PolyF (ApplyA ((,) a) p) y
scaleAP a = applyAP ((,) a)
getScaleAP :: Prf p -> PolyF (ApplyA ((,) a) p) y -> a
getScaleAP PrfNil p = case p of {}
getScaleAP (PrfCons _) (Y (a, _) _) = a
getScaleAP (PrfCons p) (N ap) = getScaleAP p ap
getUnscaledAP :: Prf ('(a, b) ': p) -> Prf q -> PolyF (ApplyA ((,) a) q) y -> PolyF q y
getUnscaledAP _ PrfNil q = case q of {}
getUnscaledAP _ (PrfCons q) (Y (_, a) by) = q // Y a by
getUnscaledAP p (PrfCons q) (N aq) = N (getUnscaledAP p q aq)
-- Products
type family (*) (p :: PolyKind) (q :: PolyKind) :: PolyKind where
'[] * q = '[]
(ab ': p) * q = (ab .* q) ++ (p * q)
prodPrf :: Prf p -> Prf q -> Prf (p * q)
prodPrf PrfNil _ = PrfNil
prodPrf abp@(PrfCons p) q = coprodPrf (scalePrf abp q) (prodPrf p q)
proj1P :: forall p q. Prf p -> Prf q -> Poly (p * q) p
proj1P PrfNil _ = PNil
proj1P (PrfCons p) q = (prfP /// (||| liftQ (proj1P p q))) (p // step q)
where
step :: forall p' q' a b. IsP p' => Prf q' -> Poly ('(a, b) .* q') ('(a, b) ': p')
step PrfNil = PNil
step (PrfCons q') = P (py Left . fst) (step q')
proj2P :: forall p q. Prf p -> Prf q -> Poly (p * q) q
proj2P PrfNil q = q // PNil
proj2P abp@(PrfCons p) q = step abp q ||| proj2P p q
where
step :: forall p' q' a b. Prf ('(a, b) ': p') -> Prf q' -> Poly ('(a, b) .* q') q'
step _ PrfNil = PNil
step p' (PrfCons q') = q' // P (py Right . snd) (liftQ $ step p' q')
(&&&) :: Poly r p -> Poly r q -> Poly r (p * q)
rp@PNil &&& rq@PNil = prodPrf (prfQ rp) (prfQ rq) // PNil
P ab rp &&& P ab' rq = P (\a -> prodF (ab a) (ab' a)) (rp &&& rq)
prodSwap :: Prf p -> Prf q -> Poly (p * q) (q * p)
prodSwap p q = proj2P p q &&& proj1P p q
prodBimap :: Poly p0 q0 -> Poly p1 q1 -> Poly (p0 * p1) (q0 * q1)
prodBimap pq0 pq1 = (pq0 `compP` proj1P p0 p1) &&& (pq1 `compP` proj2P p0 p1)
where
p0 = prfP pq0
p1 = prfP pq1
proj1 :: forall p q. (IsP p, IsP q) => Poly (p * q) p
proj1 = proj1P @p @q prf prf
proj2 :: forall p q. (IsP p, IsP q) => Poly (p * q) q
proj2 = proj2P @p @q prf prf
proj1F :: Prf p -> Prf q -> (p * q) ~> p
proj1F p q = fromPoly (proj1P p q)
proj2F :: Prf p -> Prf q -> (p * q) ~> q
proj2F p q = fromPoly (proj2P p q)
prodF :: PolyF p y -> PolyF q y -> PolyF (p * q) y
prodF p@(Y pa pby) q = let pq = scaleP pa pby q in inj1F (prfF pq) (prodPrf (prfTail (prfF p)) (prfF q)) pq
prodF abp@(N p) q = let pq = prodF p q in inj2F (scalePrf (prfF abp) (prfF q)) (prfF pq) pq
-- Parallel or Dirichlet product
type ParMono a b q = Apply ((,) a) ((,) b) q
type family X (p :: PolyKind) (q :: PolyKind) :: PolyKind where
'[] `X` q = '[]
('(a, b) ': p) `X` q = ParMono a b q ++ (p `X` q)
parMonoPrf :: forall a b p q. Prf ('(a, b) ': p) -> Prf q -> Prf (ParMono a b q)
parMonoPrf p q = scaleAPrf p (applyBPrf @((,) b) q)
parProdPrf :: Prf p -> Prf q -> Prf (p `X` q)
parProdPrf PrfNil _ = PrfNil
parProdPrf abp@(PrfCons p) q = coprodPrf (parMonoPrf abp q) (parProdPrf p q)
parProdF :: PolyF p py -> PolyF q qy -> PolyF (p `X` q) (py, qy)
parProdF p@(Y pa pby) q = let pq = scaleAP pa (applyBP (bimap pby) q) in inj1F (prfF pq) (parProdPrf (prfTail (prfF p)) (prfF q)) pq
parProdF abp@(N p) q = let pq = parProdF p q in inj2F (parMonoPrf (prfF abp) (prfF q)) (prfF pq) pq
parProdBimap :: Poly p0 q0 -> Poly p1 q1 -> Poly (p0 `X` p1) (q0 `X` q1)
parProdBimap pq0 pq1 = parProdPrf (prfQ pq0) (prfQ pq1) // parProdBimap' pq0 pq1
where
parProdBimap' :: IsP (q0 `X` q1) => Poly p0 q0 -> Poly p1 q1 -> Poly (p0 `X` p1) (q0 `X` q1)
parProdBimap' PNil _ = PNil
parProdBimap' (P ab pq0') pq1' = step ab pq1' ||| parProdBimap' pq0' pq1'
step :: IsP (q0 `X` q1) => (a -> PolyF q0 b) -> Poly p1 q1 -> Poly (ParMono a b p1) (q0 `X` q1)
step _ PNil = PNil
step ab0 (P ab1 pq1') = P (\(a0, a1) -> parProdF (ab0 a0) (ab1 a1)) (step ab0 pq1')
dualParMono :: Poly (Mono a b `X` Mono b a) Y
dualParMono = P (\(a, b) -> mkY (b, a)) PNil
dualParDuo :: Poly (Duo a b c d `X` Mono (b, d) (Either a c)) Y
dualParDuo
= P (\(a, (b, _)) -> mkY (b, Left a))
$ P (\(c, (_, d)) -> mkY (d, Right c))
$ PNil
dualParDuo' :: Poly (Mono (b, d) (Either a c) `X` Duo a b c d) Y
dualParDuo'
= P (\((b, _), a) -> mkY (Left a, b))
$ P (\((_, d), c) -> mkY (Right c, d))
$ PNil
-- Composition
class CanExp b where
type (p :: PolyKind) ^. b :: PolyKind
expPrf :: Prf p -> Prf (p ^. b)
expF :: (b -> PolyF p y) -> PolyF (p ^. b) y
indexF :: Prf p -> PolyF (p ^. b) y -> b -> PolyF p y
instance CanExp (Fin 'Z) where
type p ^. Fin 'Z = I
expPrf _ = prf
expF _ = Y () absurd
indexF _ _ = Fin.absurd
instance CanExp (Fin ('S 'Z)) where
type p ^. Fin ('S 'Z) = p
expPrf p = p
expF f = f FZ
indexF _ p _ = p
instance CanExp (Fin ('S n)) => CanExp (Fin ('S ('S n))) where
type p ^. Fin ('S ('S n)) = p * (p ^. Fin ('S n))
expPrf p = prodPrf p (expPrf @(Fin ('S n)) p)
expF f = prodF (f FZ) (expF (f . FS))
indexF p pb FZ = proj1F p (expPrf @(Fin ('S n)) p) pb
indexF p pb (FS n) = indexF p (proj2F p (expPrf @(Fin ('S n)) p) pb) n
instance CanExp Void where
type p ^. Void = I
expPrf _ = prf
expF _ = Y () absurd
indexF _ _ = absurd
instance CanExp () where
type p ^. () = p
expPrf p = p
expF f = f ()
indexF _ p _ = p
instance (CanExp a, CanExp b) => CanExp (Either a b) where
type p ^. Either a b = (p ^. a) * (p ^. b)
expPrf p = prodPrf (expPrf @a p) (expPrf @b p)
expF f = prodF (expF (f . Left)) (expF (f . Right))
indexF p pe (Left a) = indexF p (proj1F (expPrf @a p) (expPrf @b p) pe) a
indexF p pe (Right b) = indexF p (proj2F (expPrf @a p) (expPrf @b p) pe) b
instance (CanExp a, CanExp b) => CanExp (a, b) where
type p ^. (a, b) = (p ^. a) ^. b
expPrf p = expPrf @b (expPrf @a p)
expF f = expF (\b -> expF (\a -> f (a, b)))
indexF p pp (a, b) = indexF p (indexF (expPrf @a p) pp b) a
type ExpMono a b q = ApplyA ((,) a) (q ^. b)
type family (<|) (p :: PolyKind) (q :: PolyKind) :: PolyKind where
'[] <| q = '[]
('(a, b) ': p) <| q = ExpMono a b q ++ (p <| q)
type AllCanExp p = AllB CanExp p
expAPrf :: forall a b p q. CanExp a => Prf ('(a, b) ': p) -> Prf q -> Prf (q ^. a)
expAPrf _ = expPrf @a
expBPrf :: forall a b p q. CanExp b => Prf ('(a, b) ': p) -> Prf q -> Prf (q ^. b)
expBPrf _ = expPrf @b
expMonoPrf :: CanExp b => Prf ('(a, b) ': p) -> Prf q -> Prf (ExpMono a b q)
expMonoPrf abp q = scaleAPrf abp (expBPrf abp q)
compPrf :: AllCanExp p => Prf p -> Prf q -> Prf (p <| q)
compPrf PrfNil _ = PrfNil
compPrf abp@(PrfCons p) q = coprodPrf (expMonoPrf abp q) (compPrf p q)
toCompF :: AllCanExp p => Prf p -> Prf q -> PolyF p (PolyF q y) -> PolyF (p <| q) y
toCompF PrfNil _ pq = case pq of {}
toCompF abp@(PrfCons p) q (Y a bqy) = inj1F (scaleAPrf abp (expBPrf abp q)) (compPrf p q) (scaleAP a (expF bqy))
toCompF abp@(PrfCons p) q (N pq) = inj2F (scaleAPrf abp (expBPrf abp q)) (compPrf p q) (toCompF p q pq)
fromCompF :: AllCanExp p => Prf p -> Prf q -> PolyF (p <| q) y -> PolyF p (PolyF q y)
fromCompF PrfNil _ pq = case pq of {}
fromCompF abp@(PrfCons p) q pq = coprodF (scaleAPrf abp (expBPrf abp q)) decompose (N . fromCompF p q) pq
where
decompose aqb = p // Y (getScaleAP (expBPrf abp q) aqb) (indexF q (getUnscaledAP abp (expBPrf abp q) aqb))
-- Cartesian closure
type family (^) (q :: PolyKind) (p :: PolyKind) :: PolyKind where
q ^ '[] = I
q ^ ('(a, b) ': p) = ((q <| Duo b Void () ()) ^. a) * (q ^ p)
fromDuoF :: PolyF (Duo a Void () ()) y -> Either y a
fromDuoF (Y a _) = Right a
fromDuoF (N (Y () by)) = Left (by ())
fromDuoF (N (N p)) = case p of {}
toDuoF :: Either y a -> PolyF (Duo a Void () ()) y
toDuoF (Right a) = Y a (\case {})
toDuoF (Left y) = N (Y () (\() -> y))
duoBPrf :: Prf ('(a, b) ': p) -> Prf (Duo b Void () ())
duoBPrf _ = PrfCons (PrfCons PrfNil)
cartClosurePrf :: (AllA CanExp p, AllB CanExp q) => Prf p -> Prf q -> Prf (q ^ p)
cartClosurePrf PrfNil _ = PrfCons PrfNil
cartClosurePrf abp@(PrfCons p) q = prodPrf (expAPrf abp (compPrf q (duoBPrf abp))) (cartClosurePrf p q)
fromCartClosure :: forall p q p'. (AllA CanExp p, AllB CanExp q) => Prf p -> Prf q -> Poly p' (q ^ p) -> Poly (p' * p) q
fromCartClosure PrfNil q PNil = q // PNil
fromCartClosure (PrfCons p) q PNil = cartClosurePrf p q // fromCartClosure p q PNil
fromCartClosure p q (P ab p'qp) = (q // step p ab) ||| fromCartClosure p q p'qp
where
step :: forall a b p1. (AllA CanExp p1, IsP q) => Prf p1 -> (a -> PolyF (q ^ p1) b) -> Poly ('(a, b) .* p1) q
step PrfNil _ = PNil
step abp@(PrfCons p1) ab1 =
let duoB = duoBPrf abp
qOfB = compPrf q duoB
qOfBPowA = expAPrf abp qOfB
cCloPQ = cartClosurePrf p1 q
in P
(\(a1, a2) -> fmap fromDuoF $ fromCompF q duoB $ indexF qOfB (proj1F qOfBPowA cCloPQ (ab1 a1)) a2)
(step p1 (proj2F qOfBPowA cCloPQ . ab1))
toCartClosure :: forall p q p'. (AllA CanExp p, AllB CanExp q) => Prf p' -> Prf p -> Prf q -> Poly (p' * p) q -> Poly p' (q ^ p)
toCartClosure PrfNil p q PNil = cartClosurePrf p q // PNil
toCartClosure abp'@(PrfCons p') p q p'qp = P (step p $ compP p'qp $ inj1P (scalePrf abp' p) (prodPrf p' p)) (toCartClosure p' p q (compP p'qp (inj2P (scalePrf abp' p) (prodPrf p' p))))
where
step :: AllA CanExp p1 => Prf p1 -> Poly ('(a, b) .* p1) q -> a -> PolyF (q ^ p1) b
step PrfNil _ _ = Y () absurd
step abp@(PrfCons p1) (P ab pq) a1 = prodF
(expF (\a2 -> toCompF q (duoBPrf abp) $ fmap toDuoF $ ab (a1, a2)))
(step p1 pq a1)
-- Dirichlet closure [–,–]
type family DClo (q :: PolyKind) (p :: PolyKind) :: PolyKind where
DClo q '[] = I
DClo q ('(a, b) ': p) = ((q <| Mono b ()) ^. a) * DClo q p
monoBPrf :: Prf ('(a, b) ': p) -> Prf (Mono b ())
monoBPrf _ = PrfCons PrfNil
diriClosurePrf :: (AllA CanExp p, AllB CanExp q) => Prf p -> Prf q -> Prf (DClo q p)
diriClosurePrf PrfNil _ = PrfCons PrfNil
diriClosurePrf abp@(PrfCons p) q = prodPrf (expAPrf abp (compPrf q (monoBPrf abp))) (diriClosurePrf p q)
fromDiriClosure :: forall p q p'. (AllA CanExp p, AllB CanExp q) => Prf p -> Prf q -> Poly p' (DClo q p) -> Poly (p' `X` p) q
fromDiriClosure PrfNil q PNil = q // PNil
fromDiriClosure (PrfCons p) q PNil = diriClosurePrf p q // fromDiriClosure p q PNil
fromDiriClosure p q (P ab p'qp) = (q // step p ab) ||| fromDiriClosure p q p'qp
where
step :: forall a b p1. (AllA CanExp p1, IsP q) => Prf p1 -> (a -> PolyF (DClo q p1) b) -> Poly (ParMono a b p1) q
step PrfNil _ = PNil
step abp@(PrfCons p1) ab1 =
let monoB = monoBPrf abp
qOfB = compPrf q monoB
qOfBPowA = expAPrf abp qOfB
dCloPQ = diriClosurePrf p1 q
in P
(\(a1, a2) -> fmap ((\(b2, fb1) -> (fb1 (), b2)) . fromMonoF) $ fromCompF q monoB $ indexF qOfB (proj1F qOfBPowA dCloPQ (ab1 a1)) a2)
(step p1 (proj2F qOfBPowA dCloPQ . ab1))
toDiriClosure :: forall p q p'. (AllA CanExp p, AllB CanExp q) => Prf p' -> Prf p -> Prf q -> Poly (p' `X` p) q -> Poly p' (DClo q p)
toDiriClosure PrfNil p q PNil = diriClosurePrf p q // PNil
toDiriClosure abp'@(PrfCons p') p q p'qp = P (step p $ compP p'qp $ inj1P (parMonoPrf abp' p) (parProdPrf p' p)) (toDiriClosure p' p q (compP p'qp (inj2P (parMonoPrf abp' p) (parProdPrf p' p))))
where
step :: AllA CanExp p1 => Prf p1 -> Poly (ParMono a b p1) q -> a -> PolyF (DClo q p1) b
step PrfNil _ _ = Y () absurd
step abp@(PrfCons p1) (P ab pq) a1 = prodF
(expF (\a2 -> toCompF q (monoBPrf abp) $ fmap (\(b1, b2) -> Y b2 (const b1)) $ ab (a1, a2)))
(step p1 pq a1)
-- Categories as comonoids in Poly
class All Eq CanExp p => Comonoid p where
unit :: Poly p Y
mult :: Poly p (p <| p)
type Obj p = PolyF p ()
instance Show (Obj '[]) where
show p = case p of {}
instance (Show (Obj p), Show a) => Show (Obj ('(a, b) ': p)) where
show (Y a _) = "Y " ++ show a
show (N p) = "N (" ++ show p ++ ")"
-- Each monomial ay^b represents a collection of @a@ objects with @b@ outgoing arrows.
-- So an arrow is a choice of monomial with a choice of source object @a@ and a choice of outgoing arrow @b@.
data Arr p where
ArrY :: IsP p => a -> b -> Arr ('(a, b) ': p)
ArrN :: Arr p -> Arr ('(a, b) ': p)
deriving instance Show (Arr '[])
deriving instance (Show (Arr p), Show a, Show b) => Show (Arr ('(a, b) ': p))
arrPrf :: Arr p -> Prf p
arrPrf ArrY{} = prf
arrPrf (ArrN p) = PrfCons (arrPrf p)
polyCatDom :: Arr p -> Obj p
polyCatDom (ArrY a _) = Y a (const ())
polyCatDom (ArrN p) = N (polyCatDom p)
polyCatCod :: Comonoid p => Arr p -> Obj p
polyCatCod arr = step mult arr arr where
step :: All Eq CanExp q => Poly p (q <| q) -> Arr p -> Arr q -> Obj q
step PNil a _ = case a of {}
step (P _ ppp) (ArrN p) q = step ppp p q
step (P f _) (ArrY a _) q = loop (fromCompF (arrPrf q) (arrPrf q) (f a)) q
where
loop :: PolyF p (PolyF q x) -> Arr p -> Obj q
loop (Y _ by) (ArrY _ b) = () <$ by b
loop (N pp) (ArrN p) = loop pp p
loop _ _ = error "Comonoid laws violated"
polyCatId :: Comonoid p => Obj p -> Arr p
polyCatId = step unit
where
step :: Poly p Y -> Obj p -> Arr p
step PNil o = case o of {}
step (P ab _) (Y a _) = ArrY a (case ab a of Y () b -> b (); N p -> case p of {})
step (P _ p) (N o) = ArrN (step p o)
polyCatComp :: Comonoid p => Arr p -> Arr p -> Maybe (Arr p)
polyCatComp arr = step mult arr arr where
step :: All Eq CanExp q => Poly p (q <| q) -> Arr p -> Arr q -> Arr q -> Maybe (Arr p)
step PNil a _ = case a of {}
step (P _ ppp) (ArrN p) q = fmap ArrN <$> step ppp p q
step (P f _) (ArrY a _) q = fmap (ArrY a) <$> loop (fromCompF (arrPrf q) (arrPrf q) (f a)) q
where
loop :: All Eq CanExp q => PolyF p (PolyF q b) -> Arr p -> Arr q -> Maybe b
loop (Y _ by) (ArrY _ b) = loop2 (by b)
loop (N pp) (ArrN p) = loop pp p
loop _ _ = error "Comonoid laws violated"
loop2 :: All Eq CanExp q => PolyF q b -> Arr q -> Maybe b
loop2 (Y a' b'y) (ArrY a'' b') = if a' == a'' then Just (b'y b') else Nothing
loop2 (N pp) (ArrN p) = loop2 pp p
loop2 _ _ = Nothing
-- A ==> C
-- | ^
-- +> B -+
data A = A deriving (Eq, Show)
data B = B deriving (Eq, Show)
data C = C deriving (Eq, Show)
type Example = '[ '(A, Fin Nat4), '(B, Fin Nat2), '(C, Fin Nat1) ]
objA, objB, objC :: Obj Example
objA = Y A (const ())
objB = N $ Y B (const ())
objC = N $ N $ Y C (const ())
idA, idB, idC, arrAB, arrBC, arrAC1, arrAC2 :: Arr Example
idA = ArrY A Fin0
arrAB = ArrY A Fin1
arrAC1 = ArrY A Fin2
arrAC2 = ArrY A Fin3
idB = ArrN $ ArrY B Fin0
arrBC = ArrN $ ArrY B Fin1
idC = ArrN $ ArrN $ ArrY C Fin0
expand :: PolyF Example (PolyF Example y) -> PolyF (Example <| Example) y
expand = toCompF (prf @Example) (prf @Example)
instance Comonoid Example where
unit = P (\A -> mkY Fin0) $ P (\B -> mkY Fin0) $ P (\C -> mkY Fin0) $ PNil
mult = P (\A -> expand $ Y A $ \case
Fin0 -> Y A id
Fin1 -> N $ Y B $ \case { Fin0 -> Fin1; Fin1 -> Fin2; _ -> err }
Fin2 -> N $ N $ Y C $ \case { Fin0 -> Fin2; _ -> err }
Fin3 -> N $ N $ Y C $ \case { Fin0 -> Fin3; _ -> err }
_ -> err)
$ P (\B -> expand $ N $ Y B $ \case
Fin0 -> N $ Y B id
Fin1 -> N $ N $ Y C $ \case { Fin0 -> Fin1; _ -> err }
_ -> err)
$ P (\C -> expand $ N $ N $ Y C $ \case
Fin0 -> N $ N $ Y C id
_ -> err)
$ PNil
pattern Fin0 :: Fin ('S n)
pattern Fin0 = FZ
pattern Fin1 :: Fin ('S ('S n))
pattern Fin1 = FS Fin0
pattern Fin2 :: Fin ('S ('S ('S n)))
pattern Fin2 = FS Fin1
pattern Fin3 :: Fin ('S ('S ('S ('S n))))
pattern Fin3 = FS Fin2
err :: a
err = error "Impossible"
-- Lenses
type Lens s t a b = s -> (a, b -> t)
fromLens :: Lens s t a b -> Poly (Mono s t) (Mono a b)
fromLens f = P (\s -> case f s of (a, bt) -> Y a bt) PNil
toLens :: Poly (Mono s t) (Mono a b) -> Lens s t a b
toLens (P qs PNil) s = case qs s of
Y a bt -> (a, bt)
N n -> case n of {}
toLens2 :: Poly (Mono s t) (Duo a0 b0 a1 b1) -> s -> Either (a0, b0 -> t) (a1, b1 -> t)
toLens2 (P qs PNil) s = case qs s of
Y a0 b0t -> Left (a0, b0t)
N (Y a1 b1t) -> Right (a1, b1t)
N (N n) -> case n of {}
eitherLens2 :: Poly (Mono (Either a0 a1) (Either b0 b1)) (Duo a0 b0 a1 b1)
eitherLens2 = P (either (\a0 -> Y a0 Left) (\a1 -> N (Y a1 Right))) PNil
-- Systems
type System s p = Poly (Mono s s) p
fromSystem :: System s p -> s -> PolyF p s
fromSystem (P sps PNil) = sps
data Stream a = Str a (Stream a)
fromSystem1 :: System s (Mono a b) -> s -> Stream b -> Stream a
fromSystem1 sys st = case fromSystem sys st of
Y a bst -> \(Str b bs) -> Str a (fromSystem1 sys (bst b) bs)
N n -> case n of {}
fromSystem2 :: System s (Duo a0 b0 a1 b1) -> s -> Stream (b0, b1) -> Stream (Either a0 a1)
fromSystem2 sys st = case fromSystem sys st of
Y a0 bst -> \(Str (b0, _) bs) -> Str (Left a0) (fromSystem2 sys (bst b0) bs)
N (Y a1 bst) -> \(Str (_, b1) bs) -> Str (Right a1) (fromSystem2 sys (bst b1) bs)
N (N n) -> case n of {}
flipflop :: System Bool (Mono Bool ())
flipflop = P (\s -> Y s (\() -> not s)) PNil
counter :: System Int (Mono Bool ())
counter = P (\n -> Y (odd n) (\() -> n + 1)) PNil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment