| Safe Haskell | None |
|---|---|
| Language | GHC2024 |
Proarrow.Tools.SMC
Description
A small HOAS front end for building morphisms in any symmetric monoidal category, the linear
counterpart of Proarrow.Tools.CCC. Each variable is used exactly once: the functions on terms
are linear, so GHC's linear types check that every variable is used once, and a Term is
indexed by its context, which is exactly the variables it uses. So a variable is the identity
on its own type, and no copying or discarding is ever generated. Terms with disjoint contexts
combine by merging the contexts, which only reorders wires. Functions on terms need
LinearTypes and linear arrows, e.g. .Term d g a %1 -> Term d g b
Types are SYN expressions, interpreted in the target category by Interp. Their tensor is a
constructor, so split can take a term's type apart, which the target's own **, a type
family, would not allow.
Every variable has an id, the number of binders around it, and a context lists its variables
by descending id. Merging compares ids, so it only reduces where the depths are known, which is
the case for terms built directly inside toSMC. A reusable piece that binds variables of its
own is compiled on its own and used through call.
The module also provides do notation, for use with QualifiedDo:
import Prelude hiding ((*)) import Proarrow.Tools.SMC (SYN (..), lift, toSMC, (*)) import Proarrow.Tools.SMC qualified as SMC rot2T = toSMC @(F a :** F b :** F c) \x -> SMC.do (b, c, a) <- lift @(F a :** F b :** F c) @(F b :** F c :** F a) rotT x c * a * b
Without the import of (*), Prelude's is used on terms, and GHC reports that as variables used
more than once (Many against One) and mismatched depths, not as a missing instance.
A bind takes its right hand side apart with a pattern of (nested) tuples, as split does, and
the rest of the block must use every variable exactly once. The argument of toSMC is such a
pattern too, as in rotT, and () there compiles a term without inputs.
With RecursiveDo, a rec block traces, so it needs a traced monoidal category. Its variables
that are used before they are bound are fed back, and the others are passed on to the rest of
the block. GHC's translation of rec passes every variable of the block to its end again,
including the ones a later statement of the block already used, so only such blocks work
where no statement uses a variable bound by an earlier one. A block of a single statement always
qualifies, and a nested pattern lets one statement bind everything:
rec ((am, bp), (bm, cp)) <- lift g (ap * bm) * lift f (bp * cm)
loop traces without GHC's translation, so it has neither restriction, but the type of the fed
back variable has to be given.
The module is inspired by Bernardy and Spiwack,
Evaluating Linear Functions to Symmetric Monoidal Categories, whose
P k r a ports correspond to Term, encode to lift, decode to toSMC, (!:) to
(*) and split to split. Unlike their implementation, it keeps the context thinned instead
of computing in the cartesian structure and arguing afterwards that the result is monoidal.
Synopsis
- data SYN k
- type family Interp (s :: SYN k) :: k where ...
- class CategoryOf k => KnownObj (s :: SYN k) where
- synOb :: forall {k} (s :: SYN k). KnownObj s => Obj (Interp s)
- data Term (d :: Nat) (g :: Ctx k) (a :: SYN k) where
- toSMC :: forall {k} (a :: SYN k) (b :: SYN k) t cont. (Monoidal k, Binds t 0 a cont ('[] :: [(Nat, SYN k)]) b) => (t %1 -> cont) -> Interp a ~> Interp b
- lift :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). CategoryOf k => (Interp a ~> Interp b) -> Term d g a %1 -> Term d g b
- dup :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). Comonoid (Interp s) => Term d g s %1 -> Term d g (s ':** s)
- drop :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). Comonoid (Interp s) => Term d g s %1 -> Term d g ('I :: SYN k)
- call :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k) t cont. (Monoidal k, Binds t 0 a cont ('[] :: [(Nat, SYN k)]) b) => (t %1 -> cont) -> Term d g a %1 -> Term d g b
- (*) :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (Monoidal k, Merge g1 g2) => Term d g1 a %1 -> Term d g2 b %1 -> Term d (Union g1 g2) (a ':** b)
- split :: forall {k} (d :: Nat) (g :: Ctx k) (r :: Ctx k) (a :: SYN k) (b :: SYN k) (c :: SYN k) (da :: Nat) (db :: Nat). (Monoidal k, KnownObj a, KnownObj b, Merge r g) => Term d g (a ':** b) %1 -> (Term da '['(d, a)] a %1 -> Term db '['(d + 1, b)] b %1 -> Term (d + 2) ('(d + 1, b) ': ('(d, a) ': r)) c) %1 -> Term d (Union r g) c
- unit :: forall {k} (d :: Nat). Monoidal k => Term d ('[] :: [(Nat, SYN k)]) ('I :: SYN k)
- lam :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (b :: SYN k) t cont. (Closed k, Binds t d a cont r b) => (t %1 -> cont) %1 -> Term d r (a ':-> b)
- loop :: forall {k} (u :: SYN k) (b :: SYN k) (d :: Nat) (r :: Ctx k) t cont. (TracedMonoidal k, KnownObj b, Binds t d u cont r (b ':** u)) => (t %1 -> cont) %1 -> Term d r b
- produce :: forall {k} (a :: SYN k) (d :: Nat). (CompactClosed k, KnownObj a) => Term d ('[] :: [(Nat, SYN k)]) (a ':** 'D a)
- annihilate :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (IsoMix k, KnownObj a, Merge g1 g2) => Consumer d g1 a %1 -> Term d g2 a %1 -> Term d (Union g1 g2) ('I :: SYN k)
- (!) :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (Closed k, KnownObj a, KnownObj b, Merge g1 g2) => Term d g1 (a ':-> b) %1 -> Term d g2 a %1 -> Term d (Union g1 g2) b
- type Consumer (d :: Nat) (g :: Ctx k) (a :: SYN k) = Term d g ('D a)
- type Command (d :: Nat) (g :: Ctx k) = Term d g ('D ('I :: SYN k))
- type (:##) (a :: SYN k) (b :: SYN k) = 'D ('D a ':** 'D b)
- cut :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (StarAutonomous k, KnownObj a, Merge g1 g2) => Consumer d g1 a %1 -> Term d g2 a %1 -> Command d (Union g1 g2)
- (|>) :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (StarAutonomous k, KnownObj a, Merge g2 g1) => Term d g1 a %1 -> Consumer d g2 a %1 -> Command d (Union g2 g1)
- accept :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) t cont. (StarAutonomous k, Binds t d a cont r ('D ('I :: SYN k))) => (t %1 -> cont) %1 -> Consumer d r a
- emit :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (da :: Nat). (StarAutonomous k, KnownObj a, KnownCtx r) => (Consumer da '['(d, 'D a)] a %1 -> Command (d + 1) ('(d, 'D a) ': r)) %1 -> Term d r a
- par :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (b :: SYN k) (da :: Nat) (db :: Nat). (StarAutonomous k, KnownObj a, KnownObj b, KnownCtx r) => (Consumer da '['(d, 'D a)] a %1 -> Consumer db '['(d + 1, 'D b)] b %1 -> Command (d + 2) ('(d + 1, 'D b) ': ('(d, 'D a) ': r))) %1 -> Term d r (a :## b)
- both :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (StarAutonomous k, KnownObj a, KnownObj b, Merge g1 g2) => Consumer d g1 a %1 -> Consumer d g2 b %1 -> Consumer d (Union g1 g2) (a :## b)
- with :: forall {k} (s :: SYN k) (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k) t1 cont1 t2 cont2. (Monoidal k, HasBinaryProducts k, Binds t1 0 s cont1 ('[] :: [(Nat, SYN k)]) a, Binds t2 0 s cont2 ('[] :: [(Nat, SYN k)]) b) => (t1 %1 -> cont1) -> (t2 %1 -> cont2) -> Term d g s %1 -> Term d g (a ':&& b)
- exl :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryProducts k, KnownObj a, KnownObj b) => Term d g (a ':&& b) %1 -> Term d g a
- exr :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryProducts k, KnownObj a, KnownObj b) => Term d g (a ':&& b) %1 -> Term d g b
- absorb :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). (HasTerminalObject k, KnownObj s) => Term d g s %1 -> Term d g ('Top :: SYN k)
- inl :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryCoproducts k, KnownObj a, KnownObj b) => Term d g a %1 -> Term d g (a ':|| b)
- inr :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryCoproducts k, KnownObj a, KnownObj b) => Term d g b %1 -> Term d g (a ':|| b)
- caseOf :: forall {k} (s :: SYN k) (a :: SYN k) (b :: SYN k) (c :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) t1 cont1 t2 cont2. (Distributive k, KnownObj s, KnownObj a, KnownObj b, Merge g1 g2, Binds t1 0 (s ':** a) cont1 ('[] :: [(Nat, SYN k)]) c, Binds t2 0 (s ':** b) cont2 ('[] :: [(Nat, SYN k)]) c) => Term d g1 s %1 -> Term d g2 (a ':|| b) %1 -> (t1 %1 -> cont1) -> (t2 %1 -> cont2) -> Term d (Union g1 g2) c
- absurd :: forall {k} (s :: SYN k) (c :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (Distributive k, KnownObj s, KnownObj c, Merge g1 g2) => Term d g1 s %1 -> Term d g2 ('Zero :: SYN k) %1 -> Term d (Union g1 g2) c
- type Ctx k = [(Nat, SYN k)]
- type family Mul (g :: Ctx k) :: SYN k where ...
- class KnownCtx (g :: Ctx k)
- ctxOb :: forall {k} (g :: Ctx k). (Monoidal k, KnownCtx g) => Obj (Interp (Mul g))
- withCtxOb :: forall {k} (g :: Ctx k) r. (Monoidal k, KnownCtx g) => (Ob (Interp (Mul g)) => r) -> r
- type family Union (g1 :: Ctx k) (g2 :: Ctx k) :: Ctx k where ...
- class (KnownCtx g1, KnownCtx g2) => Merge (g1 :: Ctx k) (g2 :: Ctx k) where
- snoc :: forall {k} (n :: Nat) (a :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownCtx g) => (Interp (Mul g) ** Interp a) ~> Interp (Mul ('(n, a) ': g))
- snoc2 :: forall {k} (n :: Nat) (a :: SYN k) (m :: Nat) (b :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownObj b, KnownCtx g) => (Interp (Mul g) ** (Interp a ** Interp b)) ~> Interp (Mul ('(m, b) ': ('(n, a) ': g)))
- push2 :: forall {k} (r :: Ctx k) (n :: Nat) (a :: SYN k) (m :: Nat) (b :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownObj b, Merge r g) => (Interp (Mul g) ~> (Interp a ** Interp b)) -> Interp (Mul (Union r g)) ~> Interp (Mul ('(m, b) ': ('(n, a) ': r)))
- (>>=) :: Bind k m t p cont r => m %1 -> (t %p -> cont) %1 -> r
- return :: forall k t (d :: Nat). (Monoidal k, RecVars k t, KnownCtx (Vars k t)) => t %1 -> Ret t (Term d (Vars k t) (Mul (Vars k t)))
- mfix :: forall {k} t (d :: Nat) (g :: Ctx k). (TracedMonoidal k, RecVars k t, Merge (Inter g (Vars k t)) (Minus g (Vars k t)), Merge (Inter g (Vars k t)) (Minus (Vars k t) g), Union (Inter g (Vars k t)) (Minus g (Vars k t)) ~ g, Union (Inter g (Vars k t)) (Minus (Vars k t) g) ~ Vars k t) => (t -> Ret t (Term d g (Mul (Vars k t)))) %1 -> Rec d t (Minus g (Vars k t)) (Minus (Vars k t) g)
- fail :: a
- class Bind k m t (p :: Multiplicity) cont r | m -> k p
- type Binds t (n :: Nat) (a :: SYN k) cont (g :: Ctx k) (b :: SYN k) = (KnownObj a, KnownCtx g, Bind k (Term (n + 1) '['(n, a)] a) t 'One cont (Term (n + 1) ('(n, a) ': g) b))
- class Pat k t (d :: Nat) (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k)
- data Ret t x
- data Rec (d :: Nat) t (g0 :: Ctx k) (outs :: Ctx k)
- class RecVars k t | t -> k
- swapT :: forall {k} (a :: k) (b :: k). (SymMonoidal k, Ob a, Ob b) => (a ** b) ~> (b ** a)
- applyT :: forall {k} (a :: k) (b :: k). (Closed k, SymMonoidal k, Ob a, Ob b) => ((a ~~> b) ** a) ~> b
- curryT :: forall {k} (a :: k) (b :: k). (Closed k, SymMonoidal k, Ob a, Ob b) => a ~> (b ~~> (a ** b))
- rotT :: forall {k} (a :: k) (b :: k) (c :: k). (SymMonoidal k, Ob a, Ob b, Ob c) => ((a ** b) ** c) ~> ((b ** c) ** a)
- traceT :: forall {k} (a :: k) (b :: k) (u :: k). (TracedMonoidal k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b
- loopT :: forall {k} (a :: k) (b :: k) (u :: k). (TracedMonoidal k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b
- loopCC :: forall {k} (a :: k) (b :: k) (u :: k). (CompactClosed k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b
- snakeT :: forall {k} (a :: k). (CompactClosed k, Ob a) => a ~> a
- snakeDualT :: forall {k} (a :: k). (CompactClosed k, Ob a) => Dual a ~> Dual a
- combineDualT :: forall {k} (a :: k) (b :: k). (CompactClosed k, Ob a, Ob b) => (Dual a ** Dual b) ~> Dual (a ** b)
- dniT :: forall {k} (a :: k). (StarAutonomous k, Ob a) => a ~> Dual (Dual a)
- dneT :: forall {k} (a :: k). (StarAutonomous k, Ob a) => Dual (Dual a) ~> a
- contraT :: forall {k} (a :: k) (b :: k). (StarAutonomous k, Ob a, Ob b) => (a ~> b) -> Dual b ~> Dual a
- parSwapT :: forall {k} (a :: k) (b :: k). (StarAutonomous k, Ob a, Ob b) => Par a b ~> Par b a
- weakDistT :: forall {k} (a :: k) (b :: k) (c :: k). (StarAutonomous k, Ob a, Ob b, Ob c) => (a ** Par b c) ~> Par (a ** b) c
- distT :: forall {k} (a :: k) (b :: k) (c :: k). (Distributive k, SymMonoidal k, Ob a, Ob b, Ob c) => (a ** (b || c)) ~> ((a ** b) || (a ** c))
- swapEitherT :: forall {k} (a :: k) (b :: k). (Distributive k, SymMonoidal k, Ob a, Ob b) => (a || b) ~> (b || a)
- bothWaysT :: forall {k} (a :: k) (b :: k). (SymMonoidal k, HasBinaryProducts k, Ob a, Ob b) => (a ** b) ~> ((a ** b) && (b ** a))
Types
Type expressions over the objects of k: an object of k, the unit, the tensor, the
internal hom and the dual, and the additives: the product and its unit Top, and the
coproduct and its unit Zero.
Constructors
| F k | |
| I | |
| (SYN k) :** (SYN k) infixl 7 | |
| (SYN k) :-> (SYN k) infixr 5 | |
| D (SYN k) | |
| (SYN k) :&& (SYN k) infixl 6 | |
| Top | |
| (SYN k) :|| (SYN k) infixl 6 | |
| Zero |
Instances
| KnownCtx ('[] :: [(Nat, SYN k)]) Source Github # | |
| (Monoidal k, KnownCtx g2) => Merge ('[] :: [(Nat, SYN k)]) (g2 :: Ctx k) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (KnownObj a, KnownCtx g) => KnownCtx ('(n, a) ': g :: [(Nat, SYN k)]) Source Github # | |
| (Monoidal k, KnownCtx ('(n, a) ': g1)) => Merge ('(n, a) ': g1 :: [(Nat, SYN k)]) ('[] :: [(Nat, SYN k)]) Source Github # | |
Defined in Proarrow.Tools.SMC Methods merge :: Interp (Mul (Union ('(n, a) ': g1) ('[] :: [(Nat, SYN k)]))) ~> (Interp (Mul ('(n, a) ': g1)) ** Interp (Mul ('[] :: [(Nat, SYN k)]))) Source Github # unmerge :: (Interp (Mul ('(n, a) ': g1)) ** Interp (Mul ('[] :: [(Nat, SYN k)]))) ~> Interp (Mul (Union ('(n, a) ': g1) ('[] :: [(Nat, SYN k)]))) Source Github # | |
| (Monoidal k, KnownObj a, KnownObj b, KnownCtx g1, KnownCtx g2, MergeBy (CmpNat n m) ('(n, a) ': g1) ('(m, b) ': g2)) => Merge ('(n, a) ': g1 :: [(Natural, SYN k)]) ('(m, b) ': g2 :: [(Natural, SYN k)]) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (Monoidal k, KnownObj a) => RecVars k (Term d '['(n, a)] a) Source Github # | |
Defined in Proarrow.Tools.SMC | |
type family Interp (s :: SYN k) :: k where ... Source Github #
The object of k a type expression stands for.
Equations
| Interp ('F a :: SYN k) = a | |
| Interp ('I :: SYN k) = Unit :: k | |
| Interp (a ':** b :: SYN k) = Interp a ** Interp b | |
| Interp (a ':-> b :: SYN k) = Interp a ~~> Interp b | |
| Interp ('D a :: SYN k) = Dual (Interp a) | |
| Interp (a ':&& b :: SYN k) = Interp a && Interp b | |
| Interp ('Top :: SYN k) = TerminalObject :: k | |
| Interp (a ':|| b :: SYN k) = Interp a || Interp b | |
| Interp ('Zero :: SYN k) = InitialObject :: k |
class CategoryOf k => KnownObj (s :: SYN k) where Source Github #
Type expressions whose Interp is an object, given that their leaves are.
Instances
| Monoidal k => KnownObj ('I :: SYN k) Source Github # | |
| HasTerminalObject k => KnownObj ('Top :: SYN k) Source Github # | |
| HasInitialObject k => KnownObj ('Zero :: SYN k) Source Github # | |
| (StarAutonomous k, KnownObj a) => KnownObj ('D a :: SYN k) Source Github # | |
| (CategoryOf k, Ob a) => KnownObj ('F a :: SYN k) Source Github # | |
| (HasBinaryProducts k, KnownObj a, KnownObj b) => KnownObj (a ':&& b :: SYN k) Source Github # | |
| (Monoidal k, KnownObj a, KnownObj b) => KnownObj (a ':** b :: SYN k) Source Github # | |
| (Closed k, KnownObj a, KnownObj b) => KnownObj (a ':-> b :: SYN k) Source Github # | |
| (HasBinaryCoproducts k, KnownObj a, KnownObj b) => KnownObj (a ':|| b :: SYN k) Source Github # | |
synOb :: forall {k} (s :: SYN k). KnownObj s => Obj (Interp s) Source Github #
The identity on the object a type expression stands for.
Terms
data Term (d :: Nat) (g :: Ctx k) (a :: SYN k) where Source Github #
A term at binding depth d with context g and type a: a morphism from the tensor of
the context to a.
Constructors
| MkTerm :: forall {k} (g :: Ctx k) (a :: SYN k) (d :: Nat). (Interp (Mul g) ~> Interp a) -> Term d g a |
Instances
| (Monoidal k, KnownObj a) => RecVars k (Term d '['(n, a)] a) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (cont ~ Term (d + PSize t) (CtxOf cont :: Ctx k) (TyOf cont :: SYN k), r ~ Term d (PCtx t d g a (CtxOf cont :: Ctx k)) (TyOf cont :: SYN k), Pat k t d g a (CtxOf cont :: Ctx k) (TyOf cont :: SYN k)) => Bind k (Term d g a) t 'One cont r Source Github # | |
| (Bind k (Term d g a) t 'One cont r', r ~ Ret tt r') => Bind k (Term d g a) t 'One (Ret tt cont) r Source Github # | The statement of a |
toSMC :: forall {k} (a :: SYN k) (b :: SYN k) t cont. (Monoidal k, Binds t 0 a cont ('[] :: [(Nat, SYN k)]) b) => (t %1 -> cont) -> Interp a ~> Interp b Source Github #
Compile a function on terms to a morphism. Its argument is a pattern, as on the left of a bind
in do notation: a variable, which must be used exactly once, () for the unit, or a pair of
patterns.
lift :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). CategoryOf k => (Interp a ~> Interp b) -> Term d g a %1 -> Term d g b Source Github #
Lift a morphism of the target category to a function on terms.
dup :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). Comonoid (Interp s) => Term d g s %1 -> Term d g (s ':** s) Source Github #
Copy a term whose type is a comonoid, in Proarrow.Tools.SMC: (x1, x2) <- dup x.
drop :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). Comonoid (Interp s) => Term d g s %1 -> Term d g ('I :: SYN k) Source Github #
Discard a term whose type is a comonoid, in Proarrow.Tools.SMC: () <- drop x.
call :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k) t cont. (Monoidal k, Binds t 0 a cont ('[] :: [(Nat, SYN k)]) b) => (t %1 -> cont) -> Term d g a %1 -> Term d g b Source Github #
(*) :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (Monoidal k, Merge g1 g2) => Term d g1 a %1 -> Term d g2 b %1 -> Term d (Union g1 g2) (a ':** b) infixl 7 Source Github #
Two terms side by side. Their contexts must be disjoint.
split :: forall {k} (d :: Nat) (g :: Ctx k) (r :: Ctx k) (a :: SYN k) (b :: SYN k) (c :: SYN k) (da :: Nat) (db :: Nat). (Monoidal k, KnownObj a, KnownObj b, Merge r g) => Term d g (a ':** b) %1 -> (Term da '['(d, a)] a %1 -> Term db '['(d + 1, b)] b %1 -> Term (d + 2) ('(d + 1, b) ': ('(d, a) ': r)) c) %1 -> Term d (Union r g) c Source Github #
Take a tensor apart: the continuation gets a variable for each side and must use both.
unit :: forall {k} (d :: Nat). Monoidal k => Term d ('[] :: [(Nat, SYN k)]) ('I :: SYN k) Source Github #
The unit, which uses no variables.
lam :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (b :: SYN k) t cont. (Closed k, Binds t d a cont r b) => (t %1 -> cont) %1 -> Term d r (a ':-> b) Source Github #
Bind a pattern, as for toSMC, whose variables the body must use exactly once. This needs the
category to be closed.
loop :: forall {k} (u :: SYN k) (b :: SYN k) (d :: Nat) (r :: Ctx k) t cont. (TracedMonoidal k, KnownObj b, Binds t d u cont r (b ':** u)) => (t %1 -> cont) %1 -> Term d r b Source Github #
Trace: bind a pattern, as for toSMC, for the value fed back, whose variables the body must
use exactly once, and return it again next to the result. This needs the category to be traced.
produce :: forall {k} (a :: SYN k) (d :: Nat). (CompactClosed k, KnownObj a) => Term d ('[] :: [(Nat, SYN k)]) (a ':** 'D a) Source Github #
A new pair of wires, a variable and its dual, from nothing: the unit of the duality. This needs the category to be compact closed.
annihilate :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (IsoMix k, KnownObj a, Merge g1 g2) => Consumer d g1 a %1 -> Term d g2 a %1 -> Term d (Union g1 g2) ('I :: SYN k) Source Github #
Join a dual and its wire into nothing: the counit of the duality, which an isomix category has.
(!) :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (Closed k, KnownObj a, KnownObj b, Merge g1 g2) => Term d g1 (a ':-> b) %1 -> Term d g2 a %1 -> Term d (Union g1 g2) b infixl 8 Source Github #
Function application. The function and its argument must have disjoint contexts.
Inputs and outputs
In a *-autonomous category a term of consumes an D aa. Terms then read as in System L
(the μμ̃-calculus): a Term produces, a Consumer consumes, and a Command is the two meeting
in a cut, a term of . A command can have any number of inputs and outputs. None of
this needs compact closure: D Iproduce does.
type Consumer (d :: Nat) (g :: Ctx k) (a :: SYN k) = Term d g ('D a) Source Github #
A consumer of a: a term of its dual.
type Command (d :: Nat) (g :: Ctx k) = Term d g ('D ('I :: SYN k)) Source Github #
A producer and a consumer meeting: a term of the unit of par.
type (:##) (a :: SYN k) (b :: SYN k) = 'D ('D a ':** 'D b) infixl 7 Source Github #
Par, the dual of the tensor of the duals, interpreted as Par.
cut :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (StarAutonomous k, KnownObj a, Merge g1 g2) => Consumer d g1 a %1 -> Term d g2 a %1 -> Command d (Union g1 g2) Source Github #
A consumer meets a producer: cut k t gives t to k, like applying a continuation. This
needs the category to be *-autonomous.
(|>) :: forall {k} (a :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (StarAutonomous k, KnownObj a, Merge g2 g1) => Term d g1 a %1 -> Consumer d g2 a %1 -> Command d (Union g2 g1) infixl 1 Source Github #
cut with the producer first, as System L writes ⟨t | k⟩: t |> k sends t into k.
accept :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) t cont. (StarAutonomous k, Binds t d a cont r ('D ('I :: SYN k))) => (t %1 -> cont) %1 -> Consumer d r a Source Github #
Bind an input: a pattern for an a, as for toSMC, whose variables the command must use
exactly once, gives a consumer of a. As logic, this refutes a.
emit :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (da :: Nat). (StarAutonomous k, KnownObj a, KnownCtx r) => (Consumer da '['(d, 'D a)] a %1 -> Command (d + 1) ('(d, 'D a) ': r)) %1 -> Term d r a Source Github #
par :: forall {k} (d :: Nat) (r :: Ctx k) (a :: SYN k) (b :: SYN k) (da :: Nat) (db :: Nat). (StarAutonomous k, KnownObj a, KnownObj b, KnownCtx r) => (Consumer da '['(d, 'D a)] a %1 -> Consumer db '['(d + 1, 'D b)] b %1 -> Command (d + 2) ('(d + 1, 'D b) ': ('(d, 'D a) ': r))) %1 -> Term d r (a :## b) Source Github #
Bind two outputs: consumers of a and of b, which the command must use exactly once each,
give a producer of their par.
both :: forall {k} (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) (a :: SYN k) (b :: SYN k). (StarAutonomous k, KnownObj a, KnownObj b, Merge g1 g2) => Consumer d g1 a %1 -> Consumer d g2 b %1 -> Consumer d (Union g1 g2) (a :## b) Source Github #
A consumer of a par from a consumer of each side. Cutting the par against the tensor of the two consumers does the same with less structure.
Additives
The additives share their context between alternatives, of which only one is used. Terms that
share variables can't both be written in a linear function, so the alternatives are functions of
their own, compiled with toSMC like the argument of call, and what they share is passed in as
one term.
with :: forall {k} (s :: SYN k) (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k) t1 cont1 t2 cont2. (Monoidal k, HasBinaryProducts k, Binds t1 0 s cont1 ('[] :: [(Nat, SYN k)]) a, Binds t2 0 s cont2 ('[] :: [(Nat, SYN k)]) b) => (t1 %1 -> cont1) -> (t2 %1 -> cont2) -> Term d g s %1 -> Term d g (a ':&& b) Source Github #
Both of two alternatives on the same input: the product. Each alternative takes the input with
a pattern, as for toSMC. This needs products.
exl :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryProducts k, KnownObj a, KnownObj b) => Term d g (a ':&& b) %1 -> Term d g a Source Github #
The first alternative of a product.
exr :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryProducts k, KnownObj a, KnownObj b) => Term d g (a ':&& b) %1 -> Term d g b Source Github #
The second alternative of a product.
absorb :: forall {k} (s :: SYN k) (d :: Nat) (g :: Ctx k). (HasTerminalObject k, KnownObj s) => Term d g s %1 -> Term d g ('Top :: SYN k) Source Github #
Use up a term into the unit of the product.
inl :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryCoproducts k, KnownObj a, KnownObj b) => Term d g a %1 -> Term d g (a ':|| b) Source Github #
The left injection into a coproduct.
inr :: forall {k} (a :: SYN k) (b :: SYN k) (d :: Nat) (g :: Ctx k). (HasBinaryCoproducts k, KnownObj a, KnownObj b) => Term d g b %1 -> Term d g (a ':|| b) Source Github #
The right injection into a coproduct.
caseOf :: forall {k} (s :: SYN k) (a :: SYN k) (b :: SYN k) (c :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k) t1 cont1 t2 cont2. (Distributive k, KnownObj s, KnownObj a, KnownObj b, Merge g1 g2, Binds t1 0 (s ':** a) cont1 ('[] :: [(Nat, SYN k)]) c, Binds t2 0 (s ':** b) cont2 ('[] :: [(Nat, SYN k)]) c) => Term d g1 s %1 -> Term d g2 (a ':|| b) %1 -> (t1 %1 -> cont1) -> (t2 %1 -> cont2) -> Term d (Union g1 g2) c Source Github #
Case analysis on a coproduct, given first a term to share between the branches. Both branches
take the pair of the shared term and the contents of their alternative with a pattern, as for
toSMC. This needs the tensor to distribute over the coproduct.
absurd :: forall {k} (s :: SYN k) (c :: SYN k) (d :: Nat) (g1 :: Ctx k) (g2 :: Ctx k). (Distributive k, KnownObj s, KnownObj c, Merge g1 g2) => Term d g1 s %1 -> Term d g2 ('Zero :: SYN k) %1 -> Term d (Union g1 g2) c Source Github #
There is no term of Zero, so from one, together with the rest of the context, anything
follows.
Contexts
type Ctx k = [(Nat, SYN k)] Source Github #
A context: the variables a term uses, each with its id and type, by descending id.
type family Mul (g :: Ctx k) :: SYN k where ... Source Github #
The type standing in for a context: the tensor of its variables' types, with the most
recently bound variable on the right. A single variable is just its type, so a variable is the
identity. The cost is that Mul ('(n, a) ': g) only reduces once g is known to be empty or
not, which ctxCase tells.
class KnownCtx (g :: Ctx k) Source Github #
A context that is known to be empty or not, all the way down.
Minimal complete definition
ctxCase
ctxOb :: forall {k} (g :: Ctx k). (Monoidal k, KnownCtx g) => Obj (Interp (Mul g)) Source Github #
The identity on the tensor of a context.
withCtxOb :: forall {k} (g :: Ctx k) r. (Monoidal k, KnownCtx g) => (Ob (Interp (Mul g)) => r) -> r Source Github #
The tensor of a context is an object.
type family Union (g1 :: Ctx k) (g2 :: Ctx k) :: Ctx k where ... Source Github #
The context of two terms used side by side.
class (KnownCtx g1, KnownCtx g2) => Merge (g1 :: Ctx k) (g2 :: Ctx k) where Source Github #
Split the tensor of a merged context into the tensors of the two contexts it came from, and
back. This is where the wires are reordered, and the only place swap is used.
Methods
merge :: Interp (Mul (Union g1 g2)) ~> (Interp (Mul g1) ** Interp (Mul g2)) Source Github #
unmerge :: (Interp (Mul g1) ** Interp (Mul g2)) ~> Interp (Mul (Union g1 g2)) Source Github #
Instances
| (Monoidal k, KnownCtx g2) => Merge ('[] :: [(Nat, SYN k)]) (g2 :: Ctx k) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (Monoidal k, KnownCtx ('(n, a) ': g1)) => Merge ('(n, a) ': g1 :: [(Nat, SYN k)]) ('[] :: [(Nat, SYN k)]) Source Github # | |
Defined in Proarrow.Tools.SMC Methods merge :: Interp (Mul (Union ('(n, a) ': g1) ('[] :: [(Nat, SYN k)]))) ~> (Interp (Mul ('(n, a) ': g1)) ** Interp (Mul ('[] :: [(Nat, SYN k)]))) Source Github # unmerge :: (Interp (Mul ('(n, a) ': g1)) ** Interp (Mul ('[] :: [(Nat, SYN k)]))) ~> Interp (Mul (Union ('(n, a) ': g1) ('[] :: [(Nat, SYN k)]))) Source Github # | |
| (Monoidal k, KnownObj a, KnownObj b, KnownCtx g1, KnownCtx g2, MergeBy (CmpNat n m) ('(n, a) ': g1) ('(m, b) ': g2)) => Merge ('(n, a) ': g1 :: [(Natural, SYN k)]) ('(m, b) ': g2 :: [(Natural, SYN k)]) Source Github # | |
Defined in Proarrow.Tools.SMC | |
snoc :: forall {k} (n :: Nat) (a :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownCtx g) => (Interp (Mul g) ** Interp a) ~> Interp (Mul ('(n, a) ': g)) Source Github #
A new variable on the right of a context: a unitor if the context was empty, and nothing otherwise.
snoc2 :: forall {k} (n :: Nat) (a :: SYN k) (m :: Nat) (b :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownObj b, KnownCtx g) => (Interp (Mul g) ** (Interp a ** Interp b)) ~> Interp (Mul ('(m, b) ': ('(n, a) ': g))) Source Github #
Two new variables on the right of a context, from their tensor: a unitor if the context was empty, and an associator otherwise.
push2 :: forall {k} (r :: Ctx k) (n :: Nat) (a :: SYN k) (m :: Nat) (b :: SYN k) (g :: Ctx k). (Monoidal k, KnownObj a, KnownObj b, Merge r g) => (Interp (Mul g) ~> (Interp a ** Interp b)) -> Interp (Mul (Union r g)) ~> Interp (Mul ('(m, b) ': ('(n, a) ': r))) Source Github #
Two new variables (n, a) and (m, b) on the right of the context r, for split. When r
is empty the pair is the whole context.
Do notation
(>>=) :: Bind k m t p cont r => m %1 -> (t %p -> cont) %1 -> r Source Github #
Bind the right hand side to the pattern of the continuation.
return :: forall k t (d :: Nat). (Monoidal k, RecVars k t, KnownCtx (Vars k t)) => t %1 -> Ret t (Term d (Vars k t) (Mul (Vars k t))) Source Github #
The end of a rec block: all its variables, as the tensor of their context.
mfix :: forall {k} t (d :: Nat) (g :: Ctx k). (TracedMonoidal k, RecVars k t, Merge (Inter g (Vars k t)) (Minus g (Vars k t)), Merge (Inter g (Vars k t)) (Minus (Vars k t) g), Union (Inter g (Vars k t)) (Minus g (Vars k t)) ~ g, Union (Inter g (Vars k t)) (Minus (Vars k t) g) ~ Vars k t) => (t -> Ret t (Term d g (Mul (Vars k t)))) %1 -> Rec d t (Minus g (Vars k t)) (Minus (Vars k t) g) Source Github #
Trace a rec block: the variables it uses before binding them are fed back.
GHC's translation of rec refers to fail, but pairs of variables always match.
class Bind k m t (p :: Multiplicity) cont r | m -> k p Source Github #
A bind in a do block: a term taken apart by a pattern, or the variables of a rec block.
The multiplicity p of the continuation depends only on the right hand side m, since GHC
needs it before it knows the rest.
Minimal complete definition
Instances
| (cont ~ Term (d + PSize t) (CtxOf cont :: Ctx k) (TyOf cont :: SYN k), r ~ Term d (PCtx t d g a (CtxOf cont :: Ctx k)) (TyOf cont :: SYN k), Pat k t d g a (CtxOf cont :: Ctx k) (TyOf cont :: SYN k)) => Bind k (Term d g a) t 'One cont r Source Github # | |
| (Bind k (Term d g a) t 'One cont r', r ~ Ret tt r') => Bind k (Term d g a) t 'One (Ret tt cont) r Source Github # | The statement of a |
| (SymMonoidal k, RecVars k t, t' ~ t, cont ~ Term (HeadId (Vars k t) + 1) (CtxOf cont :: Ctx k) (TyOf cont :: SYN k), r ~ Term d (Union (Minus (CtxOf cont :: Ctx k) outs) g0) (TyOf cont :: SYN k), AllIn outs (CtxOf cont :: Ctx k), NoneIn (Minus (CtxOf cont :: Ctx k) outs) (Vars k t), Merge (Minus (CtxOf cont :: Ctx k) outs) g0, Merge (Minus (CtxOf cont :: Ctx k) outs) outs, (CtxOf cont :: Ctx k) ~ Union (Minus (CtxOf cont :: Ctx k) outs) outs) => Bind k (Rec d t g0 outs) t' 'Many cont r Source Github # | The rest of the |
type Binds t (n :: Nat) (a :: SYN k) cont (g :: Ctx k) (b :: SYN k) = (KnownObj a, KnownCtx g, Bind k (Term (n + 1) '['(n, a)] a) t 'One cont (Term (n + 1) ('(n, a) ': g) b)) Source Github #
The pattern t of a binder: it takes apart the variable (n, a), and the binder's body
cont then gives a term at depth n + 1 with type b, whose context is that variable and g.
Both the variable's type and the rest of the context must be known.
class Pat k t (d :: Nat) (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github #
A pattern: a variable, (), or a pair of patterns. A triple or quadruple stands for pairs
nested to the left, as a is: :** b :** c(x, y, z) is ((x, y), z). Binding it at depth
d to a term with context g and type a, with a continuation with context g' and type c.
Minimal complete definition
pat
Instances
| (Monoidal k, a ~ ('I :: SYN k), KnownObj c, Merge g g') => Pat k () d (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github # | The pattern |
| t ~ Term (DepthOf t) g a => Pat k t d (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github # | |
| (Monoidal k, a ~ (a1 ':** a2), KnownObj a1, KnownObj a2, Pat k x (d + 2) '['(d, a1)] a1 (PCtx y ((d + 2) + PSize x) '['(d + 1, a2)] a2 g') c, Pat k y ((d + 2) + PSize x) '['(d + 1, a2)] a2 g' c, (((d + 2) + PSize x) + PSize y) ~ (d + PSize (x, y)), PCtxPair x y d a1 a2 g' ~ ('(d + 1, a2) ': ('(d, a1) ': Drop2 (PCtxPair x y d a1 a2 g'))), Merge (Drop2 (PCtxPair x y d a1 a2 g')) g) => Pat k (x, y) d (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github # | |
| Pat k ((x, y), z) d g a g' c => Pat k (x, y, z) d (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github # | |
| Pat k (((w, x), y), z) d g a g' c => Pat k (w, x, y, z) d (g :: Ctx k) (a :: SYN k) (g' :: Ctx k) (c :: SYN k) Source Github # | |
data Rec (d :: Nat) t (g0 :: Ctx k) (outs :: Ctx k) Source Github #
A rec block after tracing, from its context without the fed back variables to the variables
it passes on.
Instances
| (SymMonoidal k, RecVars k t, t' ~ t, cont ~ Term (HeadId (Vars k t) + 1) (CtxOf cont :: Ctx k) (TyOf cont :: SYN k), r ~ Term d (Union (Minus (CtxOf cont :: Ctx k) outs) g0) (TyOf cont :: SYN k), AllIn outs (CtxOf cont :: Ctx k), NoneIn (Minus (CtxOf cont :: Ctx k) outs) (Vars k t), Merge (Minus (CtxOf cont :: Ctx k) outs) g0, Merge (Minus (CtxOf cont :: Ctx k) outs) outs, (CtxOf cont :: Ctx k) ~ Union (Minus (CtxOf cont :: Ctx k) outs) outs) => Bind k (Rec d t g0 outs) t' 'Many cont r Source Github # | The rest of the |
class RecVars k t | t -> k Source Github #
The variables of a rec block, as GHC tuples them up.
Minimal complete definition
recVars, consume
Instances
| (RecVars k x, RecVars k y) => RecVars k (x, y) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (RecVars k x, RecVars k y, RecVars k z) => RecVars k (x, y, z) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (Monoidal k, KnownObj a) => RecVars k (Term d '['(n, a)] a) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (RecVars k x, RecVars k y, RecVars k z, RecVars k w) => RecVars k (x, y, z, w) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (RecVars k x, RecVars k y, RecVars k z, RecVars k w, RecVars k v) => RecVars k (x, y, z, w, v) Source Github # | |
Defined in Proarrow.Tools.SMC | |
| (RecVars k x, RecVars k y, RecVars k z, RecVars k w, RecVars k v, RecVars k u) => RecVars k (x, y, z, w, v, u) Source Github # | |
Defined in Proarrow.Tools.SMC | |
Examples
swapT :: forall {k} (a :: k) (b :: k). (SymMonoidal k, Ob a, Ob b) => (a ** b) ~> (b ** a) Source Github #
Swap a tensor.
>>>import Prelude (Bool (..))>>>swapT @Bool @Bool (True, False)(False,True)
applyT :: forall {k} (a :: k) (b :: k). (Closed k, SymMonoidal k, Ob a, Ob b) => ((a ~~> b) ** a) ~> b Source Github #
Apply a function to an argument, both in a tensor.
>>>import Prelude (Bool (..), not)>>>applyT @Bool @Bool (not, True)False
curryT :: forall {k} (a :: k) (b :: k). (Closed k, SymMonoidal k, Ob a, Ob b) => a ~> (b ~~> (a ** b)) Source Github #
Curry the tensor.
>>>import Prelude (Bool (..))>>>curryT @Bool @Bool True False(True,False)
rotT :: forall {k} (a :: k) (b :: k) (c :: k). (SymMonoidal k, Ob a, Ob b, Ob c) => ((a ** b) ** c) ~> ((b ** c) ** a) Source Github #
Rotate a triple, with a triple pattern.
>>>import Prelude (Bool (..), Int)>>>rotT @Int @Bool @Int ((1, True), 2)((True,2),1)
traceT :: forall {k} (a :: k) (b :: k) (u :: k). (TracedMonoidal k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b Source Github #
Trace out u with a rec block. In Type the trace is a lazy fixed point.
>>>import Prelude (Int, take)>>>traceT @Int @[Int] @[Int] (\(a, u) -> (take 3 u, a : u)) 1[1,1,1]
loopT :: forall {k} (a :: k) (b :: k) (u :: k). (TracedMonoidal k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b Source Github #
Trace out u with loop.
>>>import Prelude (Int, take)>>>loopT @Int @[Int] @[Int] (\(a, u) -> (take 3 u, a : u)) 1[1,1,1]
loopCC :: forall {k} (a :: k) (b :: k) (u :: k). (CompactClosed k, Ob a, Ob b, Ob u) => ((a ** u) ~> (b ** u)) -> a ~> b Source Github #
A trace from the duality alone, so for any compact closed category: feed u in along one
end of a new pair and join its new value with the other end.
snakeT :: forall {k} (a :: k). (CompactClosed k, Ob a) => a ~> a Source Github #
A snake: create a pair, join its dual with the input, and continue with the other end. By the zigzag law it is the identity. The input is older than the pair, so it sits to the left of it, and the join needs a swap.
snakeDualT :: forall {k} (a :: k). (CompactClosed k, Ob a) => Dual a ~> Dual a Source Github #
The snake on the dual: join the input with the first end of a new pair, and continue with the second. Here the wires meet in the order they come, so no swap is needed.
combineDualT :: forall {k} (a :: k) (b :: k). (CompactClosed k, Ob a, Ob b) => (Dual a ** Dual b) ~> Dual (a ** b) Source Github #
The inverse of distribDual: make a pair for a ** b, and annihilate the two halves of its
plain end with the given duals.
dniT :: forall {k} (a :: k). (StarAutonomous k, Ob a) => a ~> Dual (Dual a) Source Github #
Double negation introduction: a consumer of a consumer of a hands it the a.
dneT :: forall {k} (a :: k). (StarAutonomous k, Ob a) => Dual (Dual a) ~> a Source Github #
Double negation elimination, the classical direction: emit an a by giving its consumer to
the input.
contraT :: forall {k} (a :: k) (b :: k). (StarAutonomous k, Ob a, Ob b) => (a ~> b) -> Dual b ~> Dual a Source Github #
Contraposition: a consumer of b consumes a through f.
parSwapT :: forall {k} (a :: k) (b :: k). (StarAutonomous k, Ob a, Ob b) => Par a b ~> Par b a Source Github #
Par is symmetric: emit both outputs and hand them to the input the other way round. This is
parSwap.
weakDistT :: forall {k} (a :: k) (b :: k) (c :: k). (StarAutonomous k, Ob a, Ob b, Ob c) => (a ** Par b c) ~> Par (a ** b) c Source Github #
Linear (weak) distributivity, a ⊗ (b ⅋ c) ⊸ (a ⊗ b) ⅋ c: the b the input emits is paired
with a and sent to the first output, and its c goes to the second. This is
weakDistL.
distT :: forall {k} (a :: k) (b :: k) (c :: k). (Distributive k, SymMonoidal k, Ob a, Ob b, Ob c) => (a ** (b || c)) ~> ((a ** b) || (a ** c)) Source Github #
The tensor distributes over the coproduct: the shared a goes to whichever branch is taken.
>>>import Prelude (Bool (..), Char, Either (..), Int)>>>distT @Int @Bool @Char (1, Left True)Left (1,True)
swapEitherT :: forall {k} (a :: k) (b :: k). (Distributive k, SymMonoidal k, Ob a, Ob b) => (a || b) ~> (b || a) Source Github #
Swap a coproduct, with nothing to share.
>>>import Prelude (Bool (..), Either (..), Int)>>>swapEitherT @Int @Bool (Left 1)Right 1
bothWaysT :: forall {k} (a :: k) (b :: k). (SymMonoidal k, HasBinaryProducts k, Ob a, Ob b) => (a ** b) ~> ((a ** b) && (b ** a)) Source Github #
A pair both as it is and swapped: each alternative takes the same pair apart in its own way.
>>>import Prelude (Bool (..), Int)>>>bothWaysT @Int @Bool (1, True)((1,True),(True,1))