Skip to content

Instantly share code, notes, and snippets.

@sjoerdvisscher
Last active July 24, 2024 12:18
Show Gist options
  • Save sjoerdvisscher/0fd871b1c2df4f4750945eb08378fb4a to your computer and use it in GitHub Desktop.
Save sjoerdvisscher/0fd871b1c2df4f4750945eb08378fb4a to your computer and use it in GitHub Desktop.
Another go at implementing polynomial functors a la David Spivak
{-# LANGUAGE GHC2021, GADTs, DataKinds #-}
{-# LANGUAGE TypeData #-}
module Endofunctors where
import Control.Comonad (Comonad(..))
import Control.Comonad.Cofree (Cofree(..))
import Control.Monad (join, ap, void)
import Control.Monad.Free (Free(..))
import Data.Bifunctor (first, second, bimap)
import Data.Functor.Day
import GHC.Generics hiding (R)
infixr 0 ~>
type p ~> q = forall y. p y -> q y
type K = Rec0
type Y = Par1
-- A monomial a*y^b
data Mono a b y = Mono a (b -> y) deriving Functor
bimapMono :: (a -> a') -> (b' -> b) -> Mono a b ~> Mono a' b'
bimapMono fa fb (Mono a by) = Mono (fa a) (by . fb)
-- Cofree comonad
cofreeHead :: Cofree p y -> y
cofreeHead (y :< _) = y
cofreeTail :: Cofree p y -> p (Cofree p y)
cofreeTail (_ :< pc) = pc
cofreeDuplicate :: Functor p => Cofree p y -> Cofree p (Cofree p y)
cofreeDuplicate c@(_ :< pc) = c :< fmap cofreeDuplicate pc
mapCofree :: Functor p => (p ~> q) -> Cofree p ~> Cofree q
mapCofree f (y :< pc) = y :< f (mapCofree f <$> pc)
runMultiple :: Comonad c => (c ~> p) -> c ~> Cofree p
runMultiple f c = extract c :< f (extend (runMultiple f) c)
microservice :: Free p `Day` Cofree q ~> Free (p `Day` q)
microservice (Day (Pure a) (b :< _) aby) = Pure (aby a b)
microservice (Day (Free pm) (_ :< qc) aby) = Free (Day pm qc $ \m c -> microservice $ Day m c aby)
swapCofree :: (Functor p, Functor q) => (q :.: p ~> p :.: q) -> q :.: Cofree p ~> Cofree p :.: q
swapCofree swap = Comp1 . go . unComp1
where
go qc =
fmap cofreeHead qc :<
fmap go (unComp1 . swap . Comp1 $ fmap cofreeTail qc)
spooling :: (Functor p, Functor q) => (q :.: p ~> p :.: q) -> Cofree (p :.: q) ~> Cofree p :.: Free q
spooling swap = Comp1 . go
where
go (y :< Comp1 pqc) =
Pure y :<
fmap (fmap Free . unComp1 . swapCofree swap . Comp1 . fmap go) pqc
spoolingTrav :: (Traversable t, Applicative f) => Cofree (f :.: t) ~> Cofree f :.: Free t
spoolingTrav = spooling (Comp1 . sequenceA . unComp1)
-- Sum and product helper functions
eitherSum :: (p y -> r) -> (q y -> r) -> (p :+: q) y -> r
eitherSum l _ (L1 p) = l p
eitherSum _ r (R1 p) = r p
bimapSum :: (p ~> p') -> (q ~> q') -> p :+: q ~> p' :+: q'
bimapSum fp _ (L1 p) = L1 (fp p)
bimapSum _ fq (R1 q) = R1 (fq q)
prodFst :: p :*: q ~> p
prodFst (p :*: _) = p
prodSnd :: p :*: q ~> q
prodSnd (_ :*: q) = q
bimapProd :: (p ~> p') -> (q ~> q') -> p :*: q ~> p' :*: q'
bimapProd fp fq (p :*: q) = fp p :*: fq q
-- Parallel or Dirichlet product as Day convolution of product
swapDay :: p `Day` q ~> q `Day` p
swapDay (Day p q f) = Day q p (flip f)
bimapDay :: (p ~> p') -> (q ~> q') -> p `Day` q ~> p' `Day` q'
bimapDay fp fq (Day p q f) = Day (fp p) (fq q) f
dualDayMono :: Mono a b `Day` Mono b a ~> Y
dualDayMono (Day (Mono a by) (Mono b ay) f) = Par1 (f (by b) (ay a))
-- Composition
bimapComp :: Functor p' => (p ~> p') -> (q ~> q') -> p :.: q ~> p' :.: q'
bimapComp fp fq = Comp1 . fmap fq . fp . unComp1
dayAsComp :: (Functor p, Functor q) => p `Day` q ~> p :.: q
dayAsComp (Day p q f) = Comp1 (fmap (\py -> fmap (f py) q) p)
duoidal :: (p :.: p') `Day` (q :.: q') ~> (p `Day` q) :.: (p' `Day` q')
duoidal (Day (Comp1 pp) (Comp1 qq) f) = Comp1 (Day pp qq (\p q -> Day p q f))
-- Endofunctor exponentiation
newtype (q ^ p) y where
Exp :: { unExp :: forall x. (y -> x) -> p x -> q x } -> (q ^ p) y
deriving instance Functor (q ^ p)
dimapExp :: (p' ~> p) -> (q ~> q') -> q ^ p ~> q' ^ p'
dimapExp fp fq (Exp f) = Exp (\ya -> fq . f ya . fp)
applyExp :: ((q ^ p) :*: p) ~> q
applyExp = uncurryExp id
unapplyExp :: Functor q => q ~> ((q :*: p) ^ p)
unapplyExp = curryExp id
curryExp :: Functor o => (o :*: p) ~> q -> o ~> (q ^ p)
curryExp f o = Exp (\ya p -> f (fmap ya o :*: p))
uncurryExp :: o ~> (q ^ p) -> (o :*: p) ~> q
uncurryExp f (o :*: p) = case f o of Exp g -> g id p
composeExp :: (q ^ p) :*: (r ^ q) ~> r ^ p
composeExp (Exp pq :*: Exp qr) = Exp (\yx -> qr yx . pq yx)
liftProd0 :: Monad t => U1 ~> t ^ Y
liftProd0 U1 = Exp (\_ (Par1 a) -> pure a)
liftProd2 :: (Monad t, Functor p, Functor q) => (t ^ p) :*: (t ^ q) ~> t ^ (p :.: q)
liftProd2 (Exp pt :*: Exp qt) = Exp
(\yx (Comp1 pq) -> join $ pt (pure . yx) $ fmap (qt yx) pq)
liftComp0 :: Monad t => Y ~> t ^ U1
liftComp0 (Par1 y) = Exp (\f U1 -> pure (f y))
liftComp2 :: (Monad t, Functor p, Functor q) => (t ^ p) :.: (t ^ q) ~> t ^ (p :*: q)
liftComp2 (Comp1 (Exp k)) = Exp
(\yx (p :*: q) -> join $ k (\(Exp f) -> f yx q) (fmap pure p))
instance (Monad t, Functor p) => Applicative (t ^ p) where
pure = dimapExp (const U1) id . liftComp0 . Par1
(<*>) = ap
instance (Monad t, Functor p) => Monad (t ^ p) where
ta >>= atb = (dimapExp (\p -> p :*: p) id . liftComp2 . Comp1) (fmap atb ta)
squared :: (t ^ K Bool) a -> (t a, t a)
squared (Exp k) = (k id (K1 False), k id (K1 True))
unsquared :: Functor t => (t a, t a) -> (t ^ K Bool) a
unsquared (l, r) = Exp (\f (K1 b) -> if b then fmap f r else fmap f l)
-- join for exponentiating by a constant is mapping join over the diagonal
testSquared :: (Monad t, Eq (t a)) => (t (t a, t a), t (t a, t a)) -> Bool
testSquared inp =
squared (join $ unsquared (bimap (fmap unsquared) (fmap unsquared) inp))
==
bimap (fst =<<) (snd =<<) inp
-- Dirichlet closure [p, q] = DClo p q
data DClo p q y where
DClo :: (forall a b. (y -> a -> b) -> p a -> q b) -> DClo p q y
deriving Functor
dimapDClo :: (p' ~> p) -> (q ~> q') -> DClo p q ~> DClo p' q'
dimapDClo fp fq (DClo f) = DClo (\k -> fq . f k . fp)
applyDClo :: (DClo p q `Day` p) ~> q
applyDClo = uncurryDClo id
unapplyDClo :: Functor q => q ~> DClo p (q `Day` p)
unapplyDClo = curryDClo id
curryDClo :: Functor o => (o `Day` p) ~> q -> o ~> DClo p q
curryDClo f o = DClo (\k p -> f (Day o p k))
uncurryDClo :: o ~> DClo p q -> (o `Day` p) ~> q
uncurryDClo f (Day o p g) = case f o of DClo h -> h g p
idDClo :: Functor p => Y ~> DClo p p
idDClo (Par1 y) = DClo (\f p -> f y <$> p)
composeDClo :: DClo q r `Day` DClo p q ~> DClo p r
composeDClo (Day (DClo qr) (DClo pq) f) = DClo (\k -> qr (\b (c, a) -> k (f b c) a) . pq (,))
multDClo :: DClo p q `Day` DClo p' q' ~> DClo (p `Day` p') (q `Day` q')
multDClo (Day (DClo pq) (DClo pq') f) = DClo (\k (Day p p' g) -> Day (pq (,) p) (pq' (,) p') (\(b, b') (c, c') -> k (f b c) (g b' c')))
dCloAsComp :: Functor q => (->) a :.: q ~> DClo ((,) a) q
dCloAsComp (Comp1 f) = DClo (\k (a, b) -> (\y -> k y b) <$> f a)
compAsDClo :: DClo ((,) a) q ~> (->) a :.: q
compAsDClo (DClo f) = Comp1 (\a -> f const (a, ()))
dCloAsComp' :: Functor q => (,) a :.: q ~> DClo ((->) a) q
dCloAsComp' (Comp1 (a, q)) = DClo (\k f -> (\y -> k y (f a)) <$> q)
data HomCoalg p q where
Hom :: (s -> DClo p q s) -> HomCoalg p q
liftHomCoalg :: Functor q => (p ~> q) -> HomCoalg p q
liftHomCoalg pq = Hom (\() -> DClo (\k -> fmap (k ()) . pq))
idHomCoalg :: Functor p => HomCoalg p p
idHomCoalg = liftHomCoalg id
compHomCoalg :: HomCoalg q r -> HomCoalg p q -> HomCoalg p r
compHomCoalg (Hom qr) (Hom pq) = Hom (\(s, t) -> composeDClo (Day (qr s) (pq t) (,)))
multHomCoalg :: HomCoalg p q -> HomCoalg p' q' -> HomCoalg (Day p p') (Day q q')
multHomCoalg (Hom pq) (Hom pq') = Hom (\(s, t) -> multDClo (Day (pq s) (pq' t) (,)))
lensHomCoalg :: ((s, p) -> (a, b -> (t, p))) -> HomCoalg (Mono s t) (Mono a b)
lensHomCoalg l = Hom (\p -> DClo (\f (Mono s ty) -> case l (s, p) of (a, btp) -> Mono a (\b -> let (t, p') = btp b in f p' (ty t))))
homCoalgLens :: HomCoalg (Mono s t) (Mono a b) -> (forall p. ((s, p) -> (a, b -> (t, p))) -> r) -> r
homCoalgLens (Hom f) k = k (\(s, p) -> case f p of DClo k' -> case k' (flip (,)) (Mono s id) of Mono a ty -> (a, ty))
-- Composition left coclosure, aka left kan extension
-- Lan q p or ⎡q⎤
-- ⎣p⎦
data Lan q p y where
Lan :: p b -> (q b -> y) -> Lan q p y
deriving instance (Functor p, Functor q) => Functor (Lan q p)
dimapLan :: (q' ~> q) -> (p ~> p') -> Lan q p ~> Lan q' p'
dimapLan fq fp (Lan p k) = Lan (fp p) (k . fq)
applyLan :: Functor p => Lan q (p :.: q) ~> p
applyLan = cocurryLan id
unapplyLan :: p ~> (Lan q p :.: q)
unapplyLan = uncocurryLan id
cocurryLan :: Functor o => p ~> (o :.: q) -> Lan q p ~> o
cocurryLan f (Lan p k) = k <$> unComp1 (f p)
uncocurryLan :: Lan q p ~> o -> p ~> (o :.: q)
uncocurryLan f p = Comp1 (f (Lan p id))
-- Lawvere theory of a monad
type Law m = Lan ([] :.: m) []
-- (forall y. [y] -> o [m y]) -> Law m y -> o y
-- (forall y. [y] -> [m y]) -> Law m y -> y
instance Monad m => Comonad (Law m) where
extract = unPar1 . cocurryLan (Comp1 . Par1 . Comp1 . map return)
duplicate = unComp1 . cocurryLan (\ys ->
Comp1 (Comp1 (
(\(Comp1 mys) ->
(\(Comp1 mms) ->
Comp1 (fmap join mms)
) <$> unComp1 (unapplyLan mys)
) <$> unComp1 (unapplyLan ys)
)))
-- Adjunctions
-- Mono _ x -| _(x)
adjAtTo :: (Mono a x ~> p) -> a -> p x
adjAtTo f a = f (Mono a id)
adjAtFrom :: Functor p => (a -> p x) -> Mono a x ~> p
adjAtFrom f (Mono a xy) = xy <$> f a
-- _(1) -| K
adjKTo :: Functor p => (p () -> a) -> p ~> K a
adjKTo f p = K1 (f (void p))
adjKFrom :: (p ~> K a) -> p () -> a
adjKFrom f p = unK1 (f p)
-- Gamma -| Mono ()
newtype Gamma p = Gamma { unGamma :: forall a. p a -> a }
adjGammaTo :: (p ~> Mono () b) -> b -> Gamma p
adjGammaTo f b = Gamma $ \p -> case f p of Mono () by -> by b
adjGammaFrom :: (b -> Gamma p) -> p ~> Mono () b
adjGammaFrom f p = Mono () (\b -> unGamma (f b) p)
-- _(1) x Gamma -| Mono
adjMonoTo :: (p ~> Mono a b) -> (p () -> a, b -> Gamma p)
adjMonoTo f = (\p -> case f p of Mono a _ -> a, \b -> Gamma $ \p -> case f p of Mono _ by -> by b)
adjMonoFrom :: Functor p => (p () -> a, b -> Gamma p) -> p ~> Mono a b
adjMonoFrom (f, g) p = Mono (f (void p)) (\b -> unGamma (g b) p)
-- Systems
-- also: p-coalgebra
type System s p = Mono s s ~> p
fromSystem :: System s p -> s -> p s
fromSystem f s = f (Mono s id)
toSystem :: Functor p => (s -> p s) -> System s p
toSystem f (Mono s sy) = sy <$> f s
data Stream a = Str a (Stream a) deriving Show
runMono :: System s (Mono a b) -> s -> Stream b -> Stream a
runMono sys s (Str b bs) = case fromSystem sys s of
Mono a by -> Str a (runMono sys (by b) bs)
seqMono :: System s0 (Mono a b) -> System s1 (Mono b c) -> System (s0, s1) (Mono a c)
seqMono s0 s1 = combineDayMonoSeq . bimapDay s0 s1 . splitDayMono
parMono :: System s0 (Mono a b) -> System s1 (Mono c d) -> System (s0, s1) (Mono (a, c) (b, d))
parMono s0 s1 = combineDayMono . bimapDay s0 s1 . splitDayMono
altMono :: System s0 (Mono a b) -> System s1 (Mono c d) -> System (s0, s1) (Mono (a, c) (Either b d))
altMono sys0 sys1 (Mono (s0, s1) f) = combineProdMono (sys0 (Mono s0 (\s0' -> f (s0', s1))) :*: sys1 (Mono s1 (\s1' -> f (s0, s1'))))
flipflop :: System Bool (Mono Bool ())
flipflop = toSystem (\b -> Mono b (const (not b)))
counter :: System Int (Mono Int Bool)
counter = toSystem (\i -> Mono i (\b -> if b then i + 1 else i))
adder :: System Int (Mono String Int)
adder = toSystem (\i -> Mono (show i) (i +))
-- State machines with internal state
data SM p = forall s. SM { transition :: System s p, initialState :: s }
mapSM :: p ~> q -> SM p -> SM q
mapSM pq (SM f s) = SM (pq . f) s
runSM :: SM p -> p (SM p)
runSM = runMapSM id
runMapSM :: (SM p -> a) -> SM p -> p a
runMapSM g (SM f s) = f (Mono s (g . SM f))
runMultipleSM :: SM p -> Cofree p (SM p)
runMultipleSM sm = sm :< runMapSM runMultipleSM sm
basicSM :: Functor p => (s -> p s) -> s -> SM p
basicSM f = SM (\(Mono s g) -> g <$> f s)
seqSM :: Functor p => SM p -> SM q -> SM (p :.: q)
seqSM (SM fp sp) (SM fq sq) = SM (bimapComp fp fq . splitCompMono) (sp, sq)
parSM :: SM p -> SM q -> SM (p `Day` q)
parSM (SM fp sp) (SM fq sq) = SM (bimapDay fp fq . splitDayMono) (sp, sq)
altSM :: SM p -> SM q -> SM (p :*: q)
altSM (SM fp sp) (SM fq sq) = SM (bimapProd fp fq . splitProdMono) (sp, sq)
newtype Mealy i o y = Mealy { unMealy :: i -> (o, y) }
deriving Functor
combineCompMealy :: Mealy a b :.: Mealy b c ~> Mealy a c
combineCompMealy (Comp1 (Mealy abm)) = Mealy $ \a -> case abm a of (b, Mealy bcy) -> bcy b
combineDayMealy :: Mealy a b `Day` Mealy c d ~> Mealy (a, c) (b, d)
combineDayMealy (Day (Mealy aby) (Mealy cdy) f) = Mealy $
\(a, c) -> case (aby a, cdy c) of
((b, ya), (d, yc)) -> ((b, d), f ya yc)
combineProdMealy :: Mealy a b :*: Mealy c d ~> Mealy (Either a c) (Either b d)
combineProdMealy (Mealy aby :*: Mealy cdy) = Mealy $ either (first Left . aby) (first Right . cdy)
basicMeally :: (s -> i -> (o, s)) -> s -> SM (Mealy i o)
basicMeally f = basicSM (Mealy . f)
runMealy :: SM (Mealy i o) -> i -> (o, SM (Mealy i o))
runMealy = unMealy . runSM
runMultipleMealy :: (Monoid o, Foldable f) => SM (Mealy i o) -> f i -> (o, SM (Mealy i o))
runMultipleMealy c = second extract . foldl (\(o, _ :< Mealy ioc) -> first (o <>) . ioc) (mempty, runMultipleSM c)
seqMealy :: SM (Mealy a b) -> SM (Mealy b c) -> SM (Mealy a c)
seqMealy s0 s1 = mapSM combineCompMealy $ seqSM s0 s1
parMealy :: SM (Mealy a b) -> SM (Mealy c d) -> SM (Mealy (a, c) (b, d))
parMealy s0 s1 = mapSM combineDayMealy $ parSM s0 s1
altMealy :: SM (Mealy a b) -> SM (Mealy c d) -> SM (Mealy (Either a c) (Either b d))
altMealy s0 s1 = mapSM combineProdMealy $ altSM s0 s1
data MultiDay ps y where
MDNil :: y -> MultiDay '[] y
MDCons :: p x -> MultiDay ps (x -> y) -> MultiDay (p ': ps) y
data TA
data TB
data TC
type Plant = Mono TC (TA, TB)
type Controller = Mono TB TC
type TheSystem = Mono TC TA
wiring :: MultiDay '[Plant, Controller] ~> TheSystem
wiring (Mono tc taby `MDCons` (Mono tb tcy `MDCons` MDNil f)) = Mono tc (\ta -> f (tcy tc) (taby (ta, tb)))
combineSumMono :: Mono a b :+: Mono c d ~> Mono (Either a c) (b, d)
combineSumMono (L1 (Mono a by)) = Mono (Left a) (by . fst)
combineSumMono (R1 (Mono c dy)) = Mono (Right c) (dy . snd)
combineProdMono :: Mono a b :*: Mono c d ~> Mono (a, c) (Either b d)
combineProdMono (Mono a by :*: Mono c dy) = Mono (a, c) (either by dy)
uncombineProdMono :: Mono (a, c) (Either b d) ~> Mono a b :*: Mono c d
uncombineProdMono (Mono (a, c) bdy) = Mono a (bdy . Left) :*: Mono c (bdy . Right)
combineDayMono :: Mono a b `Day` Mono c d ~> Mono (a, c) (b, d)
combineDayMono (Day (Mono a by) (Mono c dy) f) = Mono (a, c) (\(b, d) -> f (by b) (dy d))
combineDayMonoSeq :: Mono a b `Day` Mono b c ~> Mono a c
combineDayMonoSeq (Day (Mono a by) (Mono b cy) f) = Mono a (f (by b) . cy)
combineCompMono :: Mono a b :.: Mono c d ~> Mono (a, b -> c) (b, d)
combineCompMono (Comp1 (Mono a bcd)) = Mono (a, \b -> case bcd b of Mono c _ -> c) (\(b, d) -> case bcd b of Mono _ dy -> dy d)
combineDCloMono :: a -> Mono a b `DClo` Mono c d ~> Mono (c, d -> b) d
combineDCloMono a (DClo f) = case f (,) (Mono a id) of Mono c dy -> Mono (c, snd . dy) (fst . dy)
combineLanMono :: Mono c b `Lan` Mono a b ~> Mono a c
combineLanMono (Lan (Mono a by) k) = Mono a (\c -> k (Mono c by))
splitCompMono :: Mono (a, c) (b, d) ~> Mono a b :.: Mono c d
splitCompMono (Mono (a, c) bdy) = Comp1 (Mono a (\b -> Mono c (\d -> bdy (b, d))))
splitDayMono :: Mono (a, c) (b, d) ~> Mono a b `Day` Mono c d
splitDayMono (Mono (a, c) f) = Day (Mono a id) (Mono c id) (curry f)
splitProdMono :: Mono (a, b) (a, b) ~> Mono a a :*: Mono b b
splitProdMono (Mono (a, b) f) = Mono a (\a' -> f (a', b)) :*: Mono b (\b' -> f (a, b'))
-- l f ~> g -> f ~> r g
-- l f ~> g -> f ~> RightAdjoint l g
data RightAdjoint l g a where
RightAdjoint :: Functor f => l f ~> g -> f a -> RightAdjoint l g a
toRightAdjoint :: Functor f => l f ~> g -> f ~> RightAdjoint l g
toRightAdjoint lfg = RightAdjoint lfg
-- f ~> r g -> l f ~> g
-- LeftAdjoint r f a -> f ~> r g -> g a
newtype LeftAdjoint r f a = LeftAdjoint {
getLeftAdjoint :: forall g. Functor g => f ~> r g -> g a
}
fromLeftAdjoint :: Functor g => f ~> r g -> LeftAdjoint r f ~> g
fromLeftAdjoint frg (LeftAdjoint k) = k frg
type Lens s t a b = Mono s t ~> Mono a b
lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
lens sa sbt (Mono s ty) = Mono (sa s) (ty . sbt s)
get :: Lens s t a b -> s -> a
get f s = case f (Mono s id) of Mono a _ -> a
set :: Lens s t a b -> s -> b -> t
set f s b = case f (Mono s id) of Mono _ ty -> ty b
lensCoprod :: Lens s t a b -> Lens s' t' a' b' -> (Mono s t :+: Mono s' t') ~> (Mono a b :+: Mono a' b')
lensCoprod l r = bimapSum l r
get' :: (Mono s t :+: Mono s' t') ~> (Mono a b :+: Mono a' b') -> (Either s s' -> Either a a')
get' f ss = case f (either (L1 . (`Mono` Left)) (R1 . (`Mono` Right)) ss) of
L1 (Mono a _) -> Left a
R1 (Mono a' _) -> Right a'
{-# LANGUAGE GHC2021 #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms #-}
{-# LANGUAGE ViewPatterns #-}
module IsCountable (IsCountable(..), pattern S, pattern Z, enumAll, absurd, Nat(..), pred) where
import Data.Kind (Type)
import Data.Void (Void)
import GHC.TypeNats (type (+))
import Prelude hiding (pred)
import Numeric.Natural (Natural)
class IsCountable s where
-- | A countable set is either empty: @Pred s ~ 'Nothing@ or one bigger than another countable set, its predecessor: @Pred s ~ 'Just p@
type Pred s :: Maybe Type
fromPredCase :: PredCase s -> s
-- | pattern match on elements of @s@
toPredCase :: s -> PredCase s
-- | An "if" based on the type of @Pred s@.
tIf :: (Pred s ~ 'Nothing => r)
-> (forall p. (Pred s ~ 'Just p, IsCountable p) => r)
-> r
absurd :: (IsCountable s, Pred s ~ 'Nothing) => s -> x
absurd = \case {}
enumAll :: forall s. IsCountable s => [s]
enumAll = tIf @s [] (Z : (S <$> enumAll))
-- | Type level size, this is SLOW on larger types.
type Size s = SIZE (Pred s)
type family SIZE ps where
SIZE 'Nothing = 0
SIZE ('Just p) = 1 + Size p
data PredCase s where
PredZ :: (Pred s ~ 'Just p, IsCountable p) => PredCase s
PredS :: (Pred s ~ 'Just p, IsCountable p) => p -> PredCase s
convPredCase :: Pred a ~ Pred b => PredCase a -> PredCase b
convPredCase PredZ = PredZ
convPredCase (PredS p) = PredS p
pred :: IsCountable s
=> (forall p. (Pred s ~ 'Just p, IsCountable p) => r) -- ^ the extra element case
-> (forall p. (Pred s ~ 'Just p, IsCountable p) => p -> r) -- ^ the lifted elements case
-> s -> r
pred z _ Z = z
pred _ s (S p) = s p
pattern Z :: IsCountable s => (Pred s ~ 'Just p, IsCountable p) => s
pattern Z <- (toPredCase -> PredZ) where Z = fromPredCase PredZ
pattern S :: IsCountable s => (Pred s ~ 'Just p, IsCountable p) => p -> s
pattern S p <- (toPredCase -> PredS p) where S p = fromPredCase (PredS p)
{-# COMPLETE Z, S #-}
data Nat = NZ | NS Nat
data Fin n where
Fz :: Fin (NS n)
Fs :: Fin n -> Fin (NS n)
instance IsCountable (Fin NZ) where
type Pred (Fin NZ) = 'Nothing
fromPredCase = \case {}
toPredCase = \case {}
tIf z _ = z
instance IsCountable (Fin n) => IsCountable (Fin (NS n)) where
type Pred (Fin (NS n)) = 'Just (Fin n)
fromPredCase PredZ = Fz
fromPredCase (PredS n) = Fs n
toPredCase Fz = PredZ
toPredCase (Fs n) = PredS n
tIf _ s = s
instance IsCountable Void where
type Pred Void = 'Nothing
fromPredCase = \case {}
toPredCase = \case {}
tIf z _ = z
instance IsCountable () where
type Pred () = 'Just Void
fromPredCase PredZ = ()
fromPredCase (PredS v) = case v of
toPredCase () = PredZ
tIf _ s = s
instance IsCountable Bool where
type Pred Bool = 'Just ()
fromPredCase PredZ = False
fromPredCase (PredS ()) = True
toPredCase False = PredZ
toPredCase True = PredS ()
tIf _ s = s
instance IsCountable Natural where
type Pred Natural = 'Just Natural
fromPredCase PredZ = 0
fromPredCase (PredS n) = n + 1
toPredCase 0 = PredZ
toPredCase n = PredS (n - 1)
tIf _ s = s
instance IsCountable a => IsCountable (Maybe a) where
type Pred (Maybe a) = 'Just a
fromPredCase PredZ = Nothing
fromPredCase (PredS a) = Just a
toPredCase = maybe PredZ PredS
tIf _ s = s
type family SUM pa b where
SUM 'Nothing b = Pred b
SUM ('Just pa) b = 'Just (Either pa b)
instance (IsCountable a, IsCountable b) => IsCountable (Either a b) where
type Pred (Either a b) = SUM (Pred a) b
fromPredCase PredZ = tIf @a (Right Z) (Left Z)
fromPredCase (PredS p) = tIf @a (Right . S) (either (Left . S) Right) $ p
toPredCase (Left a) = case toPredCase a of PredZ -> PredZ; PredS pa -> PredS (Left pa)
toPredCase (Right b) = tIf @a (convPredCase $ toPredCase b) (PredS $ Right b)
tIf z s = tIf @a (tIf @b z s) s
-- type Fin2 = Bool
-- type Fin3 = Maybe Bool
-- type Fin4 = (Fin2, Fin2)
-- type Fin16 = (Fin4, Fin4)
-- type Fin256 = Fin4 -> Fin4
-- type Fin65536 = (Fin256, Fin256)
-- type Fin4294967296 = (Fin65536, Fin65536)
{-# LANGUAGE GHC2021, LambdaCase, DataKinds, TypeFamilies, UndecidableInstances, AllowAmbiguousTypes, PatternSynonyms, ViewPatterns #-}
{-# LANGUAGE BlockArguments #-}
module IsPoly where
import Control.Comonad.Cofree (Cofree(..))
import Control.Monad.Free (Free(..))
import Data.Functor.Day
import Data.Kind (Type, Constraint)
import Data.Void (Void)
import Data.Type.Ord
import GHC.Generics
import GHC.TypeLits (Symbol, AppendSymbol, ConsSymbol, )
import qualified GHC.TypeLits as N
import Prelude hiding (pred)
import IsCountable
import Endofunctors
-- A polynomial is either empty, or it is a sum of a monomial a*y^b and another polynomial
data PolyCase p y where
PCHead :: (Uncons p ~ 'Just '(a, b, q), IsPoly q) => a -> (b -> y) -> PolyCase p y
PCTail :: (Uncons p ~ 'Just '(a, b, q), IsPoly q) => q y -> PolyCase p y
convCase :: Uncons p ~ Uncons q => PolyCase p y -> PolyCase q y
convCase (PCHead a by) = PCHead a by
convCase (PCTail qy) = PCTail qy
class Functor p => IsPoly p where
type Uncons p :: Maybe (Type, Type, Type -> Type)
constr :: PolyCase p y -> p y
destr :: p y -> PolyCase p y
tyRep :: TyRep p
pattern Head :: IsPoly p => (Uncons p ~ 'Just '(a, b, q), IsPoly q) => a -> (b -> y) -> p y
pattern Head a by <- (destr -> PCHead a by)
where
Head a by = constr (PCHead a by)
pattern Tail :: IsPoly p => (Uncons p ~ 'Just '(a, b, q), IsPoly q) => q y -> p y
pattern Tail qy <- (destr -> PCTail qy)
where
Tail qy = constr (PCTail qy)
{-# COMPLETE Head, Tail #-}
data TyRep p where
TyN :: Uncons p ~ 'Nothing => TyRep p
TyJ :: forall a b p' p. (Uncons p ~ 'Just '(a, b, p'), IsPoly p') => TyRep p
tyCase
:: forall p r. IsPoly p
=> (Uncons p ~ 'Nothing => r)
-> (forall a b p'. (Uncons p ~ 'Just '(a, b, p'), IsPoly p') => r)
-> r
tyCase n j = case tyRep @p of
TyN -> n
TyJ -> j
convRep :: Uncons p ~ Uncons q => TyRep p -> TyRep q
convRep TyN = TyN
convRep TyJ = TyJ
-- Morphisms between polynomial functors, aka dependent lenses
data Poly p q where
PNil :: (Uncons p ~ 'Nothing, IsPoly p, IsPoly q) => Poly p q
P :: (Uncons p ~ 'Just '(a, b, p'), IsPoly p, IsPoly q) => (a -> q b) -> Poly p' q -> Poly p q
toPoly :: forall p q. (IsPoly p, IsPoly q) => p ~> q -> Poly p q
toPoly f = tyCase @p PNil (P (\a -> f (Head a id)) (toPoly (f . Tail)))
fromPoly :: Poly p q -> p ~> q
fromPoly PNil = absurd1
fromPoly (P aqb p'q) = \case
Head a by -> by <$> aqb a
Tail p' -> fromPoly p'q p'
type AllA c p = ALLA c (Uncons p)
type family ALLA (c :: Type -> Constraint) p :: Constraint where
ALLA c 'Nothing = ()
ALLA c ('Just '(a, b, p)) = (c a, AllA c p)
type AllB c p = ALLB c (Uncons p)
type family ALLB (c :: Type -> Constraint) p :: Constraint where
ALLB c 'Nothing = ()
ALLB c ('Just '(a, b, p)) = (c b, AllB c p)
fmapDefault :: IsPoly p => (x -> y) -> p x -> p y
fmapDefault f (Head a by) = Head a (f . by)
fmapDefault f (Tail qy) = Tail (fmapDefault f qy)
absurd1 :: (IsPoly p, Uncons p ~ 'Nothing) => p y -> r
absurd1 p = case destr p of
instance IsPoly (Mono a b) where
type Uncons (Mono a b) = 'Just '(a, b, V1)
constr (PCHead a by) = Mono a by
constr (PCTail q) = case q of {}
destr (Mono a by) = PCHead a by
tyRep = TyJ
instance IsPoly V1 where
type Uncons V1 = 'Nothing
constr = \case {}
destr = \case {}
tyRep = TyN
instance IsPoly U1 where
type Uncons U1 = 'Just '((), Void, V1)
constr (PCHead () _) = U1
constr (PCTail q) = case q of {}
destr U1 = PCHead () (\case {})
tyRep = TyJ
instance IsPoly (Rec0 a) where
type Uncons (Rec0 a) = 'Just '(a, Void, V1)
constr (PCHead a _) = K1 a
constr (PCTail q) = case q of {}
destr (K1 a) = PCHead a (\case {})
tyRep = TyJ
instance IsPoly Par1 where
type Uncons Par1 = 'Just '((), (), V1)
constr (PCHead () by) = Par1 (by ())
constr (PCTail q) = case q of {}
destr (Par1 y) = PCHead () (const y)
tyRep = TyJ
instance IsPoly Maybe where
type Uncons Maybe = 'Just '((), Void, Par1)
constr (PCHead () _) = Nothing
constr (PCTail (Par1 y)) = Just y
destr = maybe (PCHead () absurd) (PCTail . Par1)
tyRep = TyJ
instance IsPoly (Either a) where
type Uncons (Either a) = 'Just '(a, Void, Par1)
constr (PCHead a _) = Left a
constr (PCTail (Par1 y)) = Right y
destr = either (\a -> PCHead a absurd) (PCTail . Par1)
tyRep = TyJ
instance IsPoly ((,) a) where
type Uncons ((,) a) = 'Just '(a, (), V1)
constr (PCHead a by) = (a, by ())
constr (PCTail q) = case q of {}
destr (a, y) = PCHead a (const y)
tyRep = TyJ
instance IsPoly [] where
type Uncons [] = 'Just '((), Void, Y :*: [])
constr (PCHead () _) = []
constr (PCTail (Par1 y :*: ys)) = y : ys
destr [] = PCHead () absurd
destr (y:ys) = PCTail (Par1 y :*: ys)
tyRep = TyJ
instance (IsPoly p, AllB IsCountable p) => IsPoly (Free p) where
type Uncons (Free p) = 'Just '((), (), p :.: Free p)
constr (PCHead () by) = Pure $ by ()
constr (PCTail (Comp1 f)) = Free f
destr (Pure y) = PCHead () (const y)
destr (Free p) = PCTail (Comp1 p)
tyRep = TyJ
(!!!) :: Cofree (Mono a b) y -> [b] -> y
(y :< _) !!! [] = y
(_ :< pcp) !!! (b:bs) = case pcp of
Head _ bcp -> bcp b !!! bs
Tail v -> case v of
instance IsPoly (Cofree (Mono a b)) where
type Uncons (Cofree (Mono a b)) = 'Just '([b] -> a, [b], V1)
constr (PCHead as bys) = bys [] :< Head (as []) (\b -> Head (as . (b:)) (bys . (b:)))
constr (PCTail q) = case q of {}
destr c@(_ :< pcp) = case pcp of
Head a _ -> PCHead (const a) (c !!!)
Tail v -> case v of
tyRep = TyJ
instance (IsPoly p, AllB IsCountable p) => IsPoly (Cofree (K a :+: p)) where
type Uncons (Cofree (K a :+: p)) = 'Just '(a, (), Y :*: (p :.: Cofree (K a :+: p)))
constr (PCHead a by) = by () :< Head a absurd
constr (PCTail (Par1 y :*: Comp1 p')) = y :< Tail (R1 p')
destr (y :< L1 (K1 a)) = PCHead a (const y)
destr (y :< R1 p) = PCTail (Par1 y :*: Comp1 p)
tyRep = TyJ
type family SUM p q where
SUM 'Nothing q = Uncons q
SUM ('Just '(a, b, p)) q = 'Just '(a, b, p :+: q)
instance (IsPoly p, IsPoly q) => IsPoly (p :+: q) where
type Uncons (p :+: q) = SUM (Uncons p) q
constr (PCHead a by) = tyCase @p (R1 $ Head a by) (L1 $ Head a by)
constr (PCTail p') = tyCase @p (R1 . Tail) (eitherSum (L1 . Tail) R1) p'
destr (L1 p) = case p of
Head a by -> PCHead a by
Tail q -> PCTail (L1 q)
destr (R1 q) = tyCase @p (convCase $ destr q) (PCTail (R1 q))
tyRep = tyCase @p (tyCase @q TyN TyJ) TyJ
data Scale a (p :: Type -> Type) y = Scale a (p y) deriving Functor
type family SCALE a p where
SCALE a 'Nothing = 'Nothing
SCALE a1 ('Just '(a2, b, p)) = 'Just '((a1, a2), b, Scale a1 p)
instance IsPoly p => IsPoly (Scale a p) where
type Uncons (Scale a p) = SCALE a (Uncons p)
constr pc = tyCase @p (case pc of {}) $ case pc of
PCHead (a0, a1) by -> Scale a0 (Head a1 by)
PCTail (Scale a q') -> Scale a (Tail q')
destr (Scale a0 p) = case p of
Head a1 by -> PCHead (a0, a1) by
Tail qy -> PCTail (Scale a0 qy)
tyRep = tyCase @p TyN TyJ
mapScale :: (p ~> q) -> Scale a p ~> Scale a q
mapScale pq (Scale a p) = Scale a (pq p)
data IncDeg b p y = IncDeg (b -> y) (p y) deriving Functor
type family INCDEG b p where
INCDEG a 'Nothing = 'Nothing
INCDEG b1 ('Just '(a, b2, p)) = 'Just '(a, Either b1 b2, IncDeg b1 p)
instance IsPoly p => IsPoly (IncDeg b p) where
type Uncons (IncDeg b p) = INCDEG b (Uncons p)
constr pc = tyCase @p (case pc of {}) $ case pc of
PCHead a by -> IncDeg (by . Left) (Head a (by . Right))
PCTail (IncDeg by q') -> IncDeg by (Tail q')
destr (IncDeg by0 p) = case p of
Head a by1 -> PCHead a (either by0 by1)
Tail qy -> PCTail (IncDeg by0 qy)
tyRep = tyCase @p TyN TyJ
mapIncDeg :: (p ~> q) -> IncDeg a p ~> IncDeg a q
mapIncDeg pq (IncDeg by p) = IncDeg by (pq p)
newtype MultDeg b p y = MultDeg (p (b -> y)) deriving Functor
type family MULTDEG b p where
MULTDEG a 'Nothing = 'Nothing
MULTDEG b1 ('Just '(a, b2, p)) = 'Just '(a, (b1, b2), MultDeg b1 p)
instance IsPoly p => IsPoly (MultDeg b p) where
type Uncons (MultDeg b p) = MULTDEG b (Uncons p)
constr pc = tyCase @p (case pc of {}) $ case pc of
PCHead a by -> MultDeg (Head a (\b0 b1 -> by (b1, b0)))
PCTail (MultDeg q'by) -> MultDeg (Tail q'by)
destr (MultDeg p) = case p of
Head a by -> PCHead a (\(b0, b1) -> by b1 b0)
Tail qy -> PCTail (MultDeg qy)
tyRep = tyCase @p TyN TyJ
mapMultDeg :: (p ~> q) -> MultDeg a p ~> MultDeg a q
mapMultDeg pq (MultDeg p) = MultDeg (pq p)
type ProdStep a b p' q = Scale a (IncDeg b q) :+: (p' :*: q)
type family PROD p q where
PROD 'Nothing q = 'Nothing
PROD ('Just '(a, b, p')) q = Uncons (ProdStep a b p' q)
fromProdStep :: (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => ProdStep a b p' q y -> (p :*: q) y
fromProdStep (L1 (Scale a (IncDeg by q))) = Head a by :*: q
fromProdStep (R1 (p' :*: q)) = Tail p' :*: q
toProdStep :: (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => (p :*: q) y -> ProdStep a b p' q y
toProdStep (p :*: q) = case p of
Head a by -> L1 (Scale a (IncDeg by q))
Tail p' -> R1 (p' :*: q)
instance (IsPoly p, IsPoly q) => IsPoly (p :*: q) where
type Uncons (p :*: q) = PROD (Uncons p) q
constr = tyCase @p (\case {}) $ fromProdStep . constr . convCase
destr = tyCase @p (\case (p :*: _) -> case p of {}) $ convCase . destr . toProdStep
tyRep = case tyRep @p of
TyN -> TyN
TyJ @a @b @p' -> convRep $ tyRep @(ProdStep a b p' q)
-- Parallel or Dirichlet product as Day convolution of product
type DayStep a b p' q = Scale a (MultDeg b q) :+: (p' `Day` q)
type family DAY p q where
DAY 'Nothing q = 'Nothing
DAY ('Just '(a, b, p')) q = Uncons (DayStep a b p' q)
fromDayStep :: forall p q a b p' y. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => DayStep a b p' q y -> (p `Day` q) y
fromDayStep (L1 (Scale pa (MultDeg qby))) = Day (Head pa id) qby (\b by -> by b)
fromDayStep (R1 (Day p q f)) = Day (Tail p) q f
toDayStep :: forall p q a b p' y. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => (p `Day` q) y -> DayStep a b p' q y
toDayStep (Day p q f) = case p of
Head pa by -> L1 (Scale pa (MultDeg $ fmap (\qy b -> f (by b) qy) q))
Tail p' -> R1 (Day p' q f)
instance (IsPoly p, IsPoly q) => IsPoly (p `Day` q) where
type Uncons (p `Day` q) = DAY (Uncons p) q
constr = tyCase @p (\case {}) $ fromDayStep . constr . convCase
destr = tyCase @p (\case {Day p _ _ -> case p of}) $ convCase . destr . toDayStep
tyRep = case tyRep @p of
TyN -> TyN
TyJ @a @b @p' -> convRep $ tyRep @(DayStep a b p' q)
-- Exponentiation by a scalar
newtype (p ^. b) y = ExpS { getExpS :: b -> p y } deriving Functor
type ExpSStep p b = p :*: (p ^. b)
type family EXPS p b where
EXPS p 'Nothing = 'Just '((), Void, V1)
EXPS p ('Just b) = Uncons (ExpSStep p b)
fromExpSStep :: (IsPoly p, IsCountable b, Pred b ~ 'Just b') => ExpSStep p b' y -> (p ^. b) y
fromExpSStep (p :*: b'p) = ExpS (\case Z -> p; S b' -> getExpS b'p b')
toExpSStep :: (IsPoly p, IsCountable b, Pred b ~ 'Just b', IsCountable b') => (p ^. b) y -> ExpSStep p b' y
toExpSStep (ExpS bp) = bp Z :*: ExpS (bp . S)
instance (IsPoly p, IsCountable b) => IsPoly (p ^. b) where
type Uncons (p ^. b) = EXPS p (Pred b)
constr = tIf @b (\case PCHead{} -> ExpS absurd; PCTail q -> absurd1 q) $ fromExpSStep . constr . convCase
destr = tIf @b (const $ PCHead () (\case {})) $ convCase . destr . toExpSStep
tyRep = tIf @b TyJ $ tyRep'
where
tyRep' :: forall b'. (Pred b ~ 'Just b', IsCountable b') => TyRep (p ^. b)
tyRep' = convRep $ tyRep @(ExpSStep p b')
mapExpS :: (p ~> p') -> p ^. b ~> p' ^. b
mapExpS f (ExpS bp) = ExpS (f . bp)
-- Composition
type CompStep a b p q = Scale a (q ^. b) :+: (p :.: q)
type family COMP p q where
COMP 'Nothing q = 'Nothing
COMP ('Just '(a, b, p)) q = Uncons (CompStep a b p q)
fromCompStep :: (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => CompStep a b p' q ~> (p :.: q)
fromCompStep (L1 (Scale a (ExpS bqy))) = Comp1 (Head a bqy)
fromCompStep (R1 (Comp1 p'qy)) = Comp1 (Tail p'qy)
toCompStep :: (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => (p :.: q) ~> CompStep a b p' q
toCompStep (Comp1 pqy) = case pqy of
Head a bqy -> L1 (Scale a (ExpS bqy))
Tail p'qy -> R1 (Comp1 p'qy)
instance (IsPoly p, IsPoly q, AllB IsCountable p) => IsPoly (p :.: q) where
type Uncons (p :.: q) = COMP (Uncons p) q
constr = tyCase @p (\case {}) $ fromCompStep . constr . convCase
destr = tyCase @p (\case {}) $ convCase . destr . toCompStep
tyRep = case tyRep @p of
TyN -> TyN
TyJ @a @b @p' -> convRep $ tyRep @(CompStep a b p' q)
bimapComp :: Functor p' => (p ~> p') -> (q ~> q') -> p :.: q ~> p' :.: q'
bimapComp fp fq = Comp1 . fmap fq . fp . unComp1
dayAsComp :: (Functor p, Functor q) => p `Day` q ~> p :.: q
dayAsComp (Day p q f) = Comp1 (fmap (\py -> fmap (f py) q) p)
duoidal :: (p :.: p') `Day` (q :.: q') ~> (p `Day` q) :.: (p' `Day` q')
duoidal (Day (Comp1 pp) (Comp1 qq) f) = Comp1 (Day pp qq (\p q -> Day p q f))
-- Exponentiation by a polynomial
type ExpStep a b p' q = ((q :.: Either b) ^. a) :*: (q ^ p')
type family EXP p q where
EXP 'Nothing q = 'Just '((), Void, V1)
EXP ('Just '(a, b, p')) q = Uncons (ExpStep a b p' q)
fromExpStep :: forall p q a b p'. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p', IsCountable a, AllB IsCountable q) => ExpStep a b p' q ~> (q ^ p)
fromExpStep (ExpS aq :*: Exp f) = Exp \yx p -> case p of
Head a bx -> either bx yx <$> unComp1 (aq a)
Tail p' -> f yx p'
toExpStep :: forall p q a b p'. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p', IsCountable a, AllB IsCountable q) => (q ^ p) ~> ExpStep a b p' q
toExpStep (Exp f) = ExpS (\a -> Comp1 (f Right (Head a Left))) :*: Exp \yx p' -> f yx (Tail p')
instance (IsPoly p, IsPoly q, AllA IsCountable p, AllB IsCountable q) => IsPoly (q ^ p) where
type Uncons (q ^ p) = EXP (Uncons p) q
constr = tyCase @p (\case PCHead{} -> Exp (const absurd1); PCTail q -> absurd1 q) $ fromExpStep . constr . convCase
destr = tyCase @p (const $ PCHead () absurd) $ convCase . destr . toExpStep
tyRep = case tyRep @p of
TyN -> TyJ
TyJ @a @b @p' -> convRep $ tyRep @(ExpStep a b p' q)
-- Dirichlet closure [p, q] = DClo p q
type DCloStep a b p' q = ((q :.: (,) b) ^. a) :*: DClo p' q
type family DCLO p q where
DCLO 'Nothing q = 'Just '((), Void, V1)
DCLO ('Just '(a, b, p')) q = Uncons (DCloStep a b p' q)
fromDCloStep :: forall p q a b p'. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p', IsCountable a, AllB IsCountable q) => DCloStep a b p' q ~> DClo p q
fromDCloStep (ExpS aq :*: DClo k) = DClo \f p ->
case p of
Head a by -> fmap (\(b, py) -> f py (by b)) (unComp1 (aq a))
Tail p' -> k f p'
toDCloStep :: forall p q a b p'. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p', IsCountable a, AllB IsCountable q) => DClo p q ~> DCloStep a b p' q
toDCloStep (DClo k) =
ExpS (\a -> Comp1 (k (\y bb -> (either id id bb, y)) (Head a Left)))
:*: DClo \f p' -> k f (Tail p')
instance (IsPoly p, IsPoly q, AllA IsCountable p, AllB IsCountable q) => IsPoly (DClo p q) where
type Uncons (DClo p q) = DCLO (Uncons p) q
constr = tyCase @p (\case PCHead{} -> DClo (const absurd1); PCTail q -> absurd1 q) $ fromDCloStep . constr . convCase
destr = tyCase @p (const $ PCHead () absurd) $ convCase . destr . toDCloStep
tyRep = case tyRep @p of
TyN -> TyJ
TyJ @a @b @p' -> convRep $ tyRep @(DCloStep a b p' q)
-- Composition left coclosure, aka left kan extension
-- Lan q p or ⎡q⎤
-- ⎣p⎦
type CoCloStep a b p' q = Mono a (q b) :+: Lan q p'
type family COCLO p q where
COCLO 'Nothing q = 'Nothing
COCLO ('Just '(a, b, p')) q = Uncons (CoCloStep a b p' q)
fromCoCloStep :: (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => CoCloStep a b p' q ~> Lan q p
fromCoCloStep (L1 (Mono a f)) = Lan (Head a id) f
fromCoCloStep (R1 (Lan p k)) = Lan (Tail p) k
toCoCloStep :: forall p q a b p'. (IsPoly p, IsPoly q, Uncons p ~ 'Just '(a, b, p'), IsPoly p') => Lan q p ~> CoCloStep a b p' q
toCoCloStep (Lan p k) = case p of
Head a by -> L1 (Mono a (k . fmap by))
Tail p' -> R1 (Lan p' k)
instance (IsPoly p, IsPoly q) => IsPoly (Lan q p) where
type Uncons (Lan q p) = COCLO (Uncons p) q
constr = tyCase @p (\case {}) $ fromCoCloStep . constr . convCase
destr = tyCase @p (\(Lan p k) -> absurd1 p) $ convCase . destr . toCoCloStep
tyRep = case tyRep @p of
TyN -> TyN
TyJ @a @b @p' -> convRep $ tyRep @(CoCloStep a b p' q)
-- Derivative of a polynomial functor
data Deriv p y where
DerivJ :: (Uncons p ~ 'Just '(a, b, p'), IsPoly p', Pred b ~ 'Just b', IsCountable b') => Mono (a, b) b' y -> Deriv p y
DerivN :: forall a b p' p y. (Uncons p ~ 'Just '(a, b, p'), IsPoly p') => Deriv p' y -> Deriv p y
deriving instance Functor p => Functor (Deriv p)
type family DERIV p where
DERIV 'Nothing = 'Nothing
DERIV ('Just '(a, b, p')) = 'Just '((a, b), DERIV' (Pred b), Deriv p')
type family DERIV' b' where
DERIV' ('Just b') = b'
DERIV' 'Nothing = Void
instance (IsPoly p, AllB IsCountable p) => IsPoly (Deriv p) where
type Uncons (Deriv p) = DERIV (Uncons p)
constr (PCHead a by) = case tyRep @p of
TyJ @a @b @p' -> tIf @b (case a of (_, b') -> case b' of) $ DerivJ $ Mono a by
constr (PCTail q) = case tyRep @p of
TyJ @a @b @p' -> tIf @b DerivN DerivN q
destr (DerivJ (Mono (a, b) b'y)) = PCHead (a, b) b'y
destr (DerivN @a @b p) = tIf @b (PCTail p) (PCTail p)
tyRep = tyCase @p TyN TyJ
b'2b :: (IsCountable b, Eq b, Pred b ~ 'Just b', IsCountable b') => b -> b' -> b
b'2b b b' = if S b' == b then Z else S b'
b'y2by :: (IsCountable b, Eq b, Pred b ~ 'Just b') => (b, y) -> (b' -> y) -> b -> y
b'y2by (b, y) b'y b' = if b' == b then y else pred (pred y b'y b) b'y b'
by2b'y :: (IsCountable b, Eq b, Pred b ~ 'Just b', IsCountable b') => b -> (b -> y) -> b' -> y
by2b'y b by b' = by (b'2b b b')
plug :: (IsPoly p, AllB IsCountable p, AllB Eq p) => Deriv p y -> y -> p y
plug (DerivJ (Mono (a, b) b'y)) y = Head a (b'y2by (b, y) b'y)
plug (DerivN p') y = Tail $ plug p' y
allDerivatives :: (IsPoly p, AllB IsCountable p, AllB Eq p) => p y -> p (Deriv p y, y)
allDerivatives (Head @_ @_ @_ @b a by) = tIf @b undefined $ Head a $ \b -> (DerivJ (Mono (a, b) (by2b'y b by)), by b)
allDerivatives (Tail py) = Tail $ fmap (\(d, y) -> (DerivN d, y)) (allDerivatives py)
around :: (IsPoly p, AllB IsCountable p, AllB Eq p) => Deriv p y -> y -> Deriv p (Deriv p y, y)
around (DerivJ @_ @_ @b (Mono (a, b) b'y)) y = DerivJ (Mono (a, b) (\b' -> let newb = b'2b b b' in (DerivJ (Mono (a, newb) (by2b'y newb $ b'y2by (b, y) b'y)), b'y b')))
around (DerivN d) y = DerivN ((\(d', y') -> (DerivN d', y')) <$> around d y)
instance IsPoly (Mealy i o) where
type Uncons (Mealy i o) = 'Just '(i -> o, i, V1)
constr (PCHead io iy) = Mealy $ \i -> (io i, iy i)
constr (PCTail q) = case q of {}
destr (Mealy ioy) = PCHead (fst . ioy) (snd . ioy)
tyRep = TyJ
type ShowPoly p = SHOW (ToTMap (Uncons p))
type family SHOW (m :: TMap) :: Symbol where
SHOW '[] = "0"
SHOW '[ba] = ShowPair ba
SHOW (ba ': m) = ShowPair ba `AppendSymbol` " + " `AppendSymbol` SHOW m
type family ShowPair ba :: Symbol where
ShowPair '(b, a) = ShowNat a `AppendSymbol` "y^" `AppendSymbol` ShowNat b
type family ShowNat (n :: N.Nat) :: Symbol where
ShowNat n = N.NatToChar (n N.+ 48) `ConsSymbol` ""
type family Simp t :: N.Nat where
Simp () = 1
Simp Void = 0
Simp (a, b) = Simp a N.* Simp b
Simp (Either a b) = Simp a N.+ Simp b
type TMap = [(N.Nat, N.Nat)]
type family InsertTMap (ba :: (N.Nat, N.Nat)) (m :: TMap) :: TMap where
InsertTMap ba '[] = '[ba]
InsertTMap '(b, a) ('(b', a') ': m) =
OrdCond (Compare b b')
('(b, a) : '(b', a') : m)
('(b, a N.+ a') : m)
('(b', a') : InsertTMap '(b, a) m)
type family ToTMap p :: TMap where
ToTMap 'Nothing = '[]
ToTMap ('Just '(a, b, q)) = InsertTMap '(Simp b, Simp a) (ToTMap (Uncons q))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment