proarrow
Safe HaskellNone
LanguageGHC2024

Proarrow.Path

Description

A profunctor-specific counterpart of Proarrow.Bicategory.Strictified, hardcoded to :.:/Id instead of an arbitrary Bicategory. A Path is a type-level list of profunctors; Fold collapses one down to the single profunctor its elements compose to. Unlike the general (strictified) version, we don't need to track identity 2-cells through the induction -- since our 2-cells are just plain Haskell functions (:~>), the identity of any composite is always definitionally \x -> x. The only real work is concatFold/splitFold, which do the actual associator/unitor reshuffling once, by induction, so that Proarrow.Squares never has to.

Synopsis

Documentation

idN :: forall {k} {k1} p (a :: k) (b :: k1). p a b -> p a b Source Github #

Identity natural transformation, used as a 2-cell between profunctors that happen to be syntactically equal.

leftUnitor :: forall {k1} {k} (p :: k1 +-> k). Profunctor p => ((Id :: k -> k -> Type) :.: p) :~> p Source Github #

leftUnitorInv :: forall {i} {j} (p :: i +-> j). Profunctor p => p :~> ((Id :: j -> j -> Type) :.: p) Source Github #

rightUnitor :: forall {k1} {k} (p :: k1 +-> k). Profunctor p => (p :.: (Id :: k1 -> k1 -> Type)) :~> p Source Github #

rightUnitorInv :: forall {i} {k} (p :: i +-> k). Profunctor p => p :~> (p :.: (Id :: i -> i -> Type)) Source Github #

associator :: forall {k1} {k2} {j} {i} (p :: k1 +-> k2) (q :: j +-> k1) (r :: i +-> j) (a :: k2) (b :: i). ((p :.: q) :.: r) a b -> (p :.: (q :.: r)) a b Source Github #

associatorInv :: forall {j1} {k} {j2} {i} (p :: j1 +-> k) (q :: j2 +-> j1) (r :: i +-> j2) (a :: k) (b :: i). (p :.: (q :.: r)) a b -> ((p :.: q) :.: r) a b Source Github #

data Path j k where Source Github #

A type-level list of profunctors, from category j to category k.

Constructors

Nil :: forall j. Path j j 
(:::) :: forall j j1 k. (j +-> j1) -> Path j1 k -> Path j k infixr 5 

type family (ps :: Path a b) +++ (qs :: Path b c) :: Path a c infixl 5 Source Github #

Instances

Instances details
type ('Nil :: Path b b) +++ (qs :: Path b c) Source Github # 
Instance details

Defined in Proarrow.Path

type ('Nil :: Path b b) +++ (qs :: Path b c) = qs
type (p '::: ps :: Path i b) +++ (qs :: Path b k) Source Github # 
Instance details

Defined in Proarrow.Path

type (p '::: ps :: Path i b) +++ (qs :: Path b k) = p '::: (ps +++ qs)

class ((as +++ bs) +++ cs) ~ (as +++ (bs +++ cs)) => Assoc (as :: Path a a1) (bs :: Path a1 b) (cs :: Path b c) Source Github #

(as +++ bs) +++ cs and as +++ (bs +++ cs) are the same Path. Proved once, up front, by (mutual) induction with IsOb's superclasses -- see there for how the induction actually goes through -- so that every other associativity fact needed anywhere in Proarrow.Squares is a free ~ coercion instead of a function call.

Instances

Instances details
(as +++ (bs +++ cs)) ~ ((as +++ bs) +++ cs) => Assoc (as :: Path a1 a2) (bs :: Path a2 b) (cs :: Path b c) Source Github # 
Instance details

Defined in Proarrow.Path

type family Fold (ps :: Path j k) :: j +-> k Source Github #

Fold a Path down to the single profunctor its elements compose to.

Instances

Instances details
type Fold ('Nil :: Path j j) Source Github # 
Instance details

Defined in Proarrow.Path

type Fold ('Nil :: Path j j) = Id :: j -> j -> Type
type Fold (p '::: (q '::: ps) :: Path i k) Source Github # 
Instance details

Defined in Proarrow.Path

type Fold (p '::: (q '::: ps) :: Path i k) = Fold (q '::: ps) :.: p
type Fold (p '::: ('Nil :: Path k k) :: Path j k) Source Github # 
Instance details

Defined in Proarrow.Path

type Fold (p '::: ('Nil :: Path k k) :: Path j k) = p

data Tag Source Github #

Which per-element property a SPath witnesses. Tight plays the role of the tight (vertical, Representable) legs of the Prof equipment; a later Cotight would do the same for Corepresentable legs.

Constructors

Prof 
Tight 

type family Sat (t :: Tag) (p :: i +-> j) Source Github #

The per-element constraint a Tag stands for. c is applied homogeneously at every element of a path, each of a (potentially) different i +-> j kind -- a genuinely impredicative use GHC's kind system can't express with c itself as the parameter, so Tag is the (monomorphic, first-order) proxy for it instead. Mirrors Proarrow.Bicategory.Sub's IsOb/SUBCAT tag mechanism.

Instances

Instances details
type Sat 'Prof (p :: j +-> k) Source Github # 
Instance details

Defined in Proarrow.Path

type Sat 'Prof (p :: j +-> k) = Profunctor p
type Sat 'Tight (p :: j +-> k) Source Github # 
Instance details

Defined in Proarrow.Path

type Sat 'Tight (p :: j +-> k) = Representable p

data SPath (t :: Tag) (ps :: Path a b) where Source Github #

Runtime witness that every element of a Path satisfies Sat t. Replaces having a separate witness type per tag (what used to be SPath/TPath), so (|||)/(===) only need one append lemma (withObAppend), not one per kind of leg.

Constructors

SNil :: forall a (t :: Tag). CategoryOf a => SPath t ('Nil :: Path a a) 
SCons :: forall {a} {a1} {b} (t :: Tag) (p :: a +-> a1) (ps1 :: Path a1 b). Sat t p => SPath t ps1 -> SPath t (p '::: ps1) 

class ((ps +++ ('Nil :: Path k k)) ~ ps, forall b c (qs :: Path k b) (rs :: Path b c). Assoc ps qs rs) => IsOb (t :: Tag) (ps :: Path j k) where Source Github #

ps is a path all of whose elements satisfy Sat t. Only two cases (Nil/Cons) are needed: the head p stays concrete at each step of withObAppend's recursion, so GHC's own instance resolution reattaches it to the recursively-derived IsOb t (ps +++ qs) for free -- it never needs to reduce ps +++ qs itself, just match the (:::) shape.

Methods

singPath :: SPath t ps Source Github #

Instances

Instances details
CategoryOf k => IsOb t ('Nil :: Path k k) Source Github # 
Instance details

Defined in Proarrow.Path

Methods

singPath :: SPath t ('Nil :: Path k k) Source Github #

(Sat t p, IsOb t ps) => IsOb t (p '::: ps :: Path j1 k) Source Github # 
Instance details

Defined in Proarrow.Path

Methods

singPath :: SPath t (p '::: ps) Source Github #

appendPath :: forall {a} {b1} {b2} (t :: Tag) (ps :: Path a b1) (qs :: Path b1 b2). SPath t ps -> SPath t qs -> SPath t (ps +++ qs) Source Github #

Concatenate two witnesses. Plain recursion, no constraint solving -- unlike withObAppend, which additionally proves IsOb t (ps +++ qs).

withAssoc :: forall {a1} {a2} {b} {c} (ps :: Path a1 a2) (qs :: Path a2 b) (rs :: Path b c) (t :: Tag) r. IsOb t ps => (Assoc ps qs rs => r) -> r Source Github #

Bring a specific instantiation of IsOb t ps's quantified Assoc ps qs rs superclass into scope. Needed explicitly: GHC won't search the superclasses of an arbitrary given constraint to solve an unrelated ~ goal, so uses of associativity (e.g. in (|||)/(===)) have to ask for it by name at the specific ps/qs/rs in play, even though the fact itself is free once asked for.

type IsPath = IsOb 'Prof :: Path j k -> Constraint Source Github #

A well-formed (horizontal) path: every element is a plain Profunctor.

type IsTight = IsOb 'Tight :: Path j k -> Constraint Source Github #

A tight (vertical) path: every element is Representable.

weakenTight :: forall {a} {b} (ps :: Path a b). SPath 'Tight ps -> SPath 'Prof ps Source Github #

A tight path is, in particular, a well-formed path (Representable implies Profunctor). Needed explicitly because different Tags don't otherwise know anything about each other.

withObAppend :: forall {j} {b} {k} (t :: Tag) (ps :: Path j b) (qs :: Path b k) r. IsOb t qs => SPath t ps -> (IsOb t (ps +++ qs) => r) -> r Source Github #

ps,qs both satisfy Sat t pointwise ⟹ so does ps +++ qs.

withFoldOb :: forall {j} {k} (ps :: Path j k) r. SPath 'Prof ps -> (Profunctor (Fold ps) => r) -> r Source Github #

Extract Profunctor evidence for Fold ps from a runtime witness.

withFoldRep :: forall {j} {k} (ps :: Path j k) r. SPath 'Tight ps -> (Representable (Fold ps) => r) -> r Source Github #

Extract Representable evidence for Fold ps from a runtime witness. The body is identical to withFoldOb's -- both just extract Sat t (Fold ps), which needs the same single-vs-multi-element case split Fold itself has -- but there's no polymorphic t anywhere that would let one definition serve both: every call site already knows its tag concretely, so there's nothing to be generic over.

concatFold :: forall {j} {b} {k} (as :: Path j b) (bs :: Path b k). SPath 'Prof as -> SPath 'Prof bs -> (Fold bs :.: Fold as) :~> Fold (as +++ bs) Source Github #

Combine the composites of two adjacent paths into the composite of their concatenation.

splitFold :: forall {i} {k1} {k2} (as :: Path i k1) (bs :: Path k1 k2). SPath 'Prof as -> SPath 'Prof bs -> Fold (as +++ bs) :~> (Fold bs :.: Fold as) Source Github #

The inverse of concatFold.

whiskerL :: forall {j} {b} {k} (xs :: Path j b) (ys :: Path b k) (zs :: Path b k). SPath 'Prof xs -> SPath 'Prof ys -> SPath 'Prof zs -> (Fold ys :~> Fold zs) -> Fold (xs +++ ys) :~> Fold (xs +++ zs) Source Github #

Apply a 2-cell inside a concatenation, on the right.

whiskerR :: forall {j} {b} {k} (xs :: Path j b) (ys :: Path j b) (zs :: Path b k). SPath 'Prof xs -> SPath 'Prof ys -> SPath 'Prof zs -> (Fold xs :~> Fold ys) -> Fold (xs +++ zs) :~> Fold (ys +++ zs) Source Github #

Apply a 2-cell inside a concatenation, on the left.