definition example program

A cartesian category is a Category with all binary products and a Terminal Object . A product type is defined by its elimination rule — the projections , — and its introduction rule: a mapping in is the same as a pair , . In Haskell, (a, b) with the pairing (x, y) and pattern matching; records name the projections: data Product a b = Pair { fst :: a, snd :: b }.

Sources: DaoFP Chapter 5 (“Product Types”, §5.1 “Cartesian Category”, “Tuple Arithmetic”, “Functoriality”, §5.2 “Duality”, §5.3 “Monoidal Category”), §6.1 (&&&, fork, bimap); 7 Sketches Definition 3.86; Kittenlab Lecture 13.

Tuple arithmetic

All laws are proved “by the mapping-in property” (the Yoneda trick, dual to that for sums):

  • — swap (x, y) = (y, x), its own inverse; arrows into and into are both determined by the same pair , and the bijection is natural under pre-composition with .
  • — the left unitor with inverse ; follows from uniqueness of the mediating arrow (DaoFP Exercise 5.1.1). Dually the right unitor (runit).
  • — the associator (assoc); the empty tuple () is the product of zero types, the unit .
  • Functoriality: for , , (bimap of the Bifunctor (,)).
  • Symmetry holds only up to isomorphism: swapping components changes how the information is accessed, not its content.

Hence is a Symmetric Monoidal Category; a category may carry several monoidal structures at once, e.g. both and . A cartesian category with exponentials is a Cartesian Closed Category; with sums as well, bicartesian closed. Mixed maps such as are built by decomposing into sums-out and products-in (DaoFP Exercise 5.1.2–DaoFP Exercise 5.1.4).

Duality

“A product is the sum with arrows reversed”: rename to in the sum diagram and read all arrows backwards. Every construction has a dual (Opposite Category). What makes sums and products feel different in programming is the asymmetry between (no incoming arrows) and (many outgoing arrows = elements). In logic a product is conjunction: to prove provide proofs of both; extract them. A Monoid Object is defined inside any cartesian (indeed monoidal) category by , .

Docs: FinSets · Limits & colimits — Kittenlab Lecture 13

using Catlab
A = FinSet(2); B = FinSet(3)
P = product(A, B)                          # A × B = FinSet(6) with proj1 (fst), proj2 (snd)
f = FinFunction([1, 2, 1], 2); g = FinFunction([3, 3, 1], 3)
h = pair(P, f, g)                          # ⟨f, g⟩ : 3 → 6
force(compose(h, proj1(P))) == f           # computation rule
# tuple arithmetic in Julia: swap, assoc
swap((x, y)) = (y, x); assoc(((a, b), c)) = (a, (b, c))
import Mathlib
#check @Prod.mk                -- introduction: (a, b)
#check @Prod.fst               -- elimination
#check @Prod.map               -- functoriality f × g
#check @Equiv.prodComm         -- α × β ≃ β × α
#check @Equiv.prodAssoc
#check @Equiv.punitProd        -- PUnit × α ≃ α  (left unitor)
#check @CategoryTheory.CartesianMonoidalCategory   -- products as a monoidal structure
mapIn :: (c -> a, c -> b) -> (c -> (a, b))          -- introduction rule
mapIn (f, g) = \c -> (f c, g c)
(&&&) :: (c -> a) -> (c -> b) -> (c -> (a, b))      -- Haskell-style
(f &&& g) c = (f c, g c)
fork :: (c -> (a, b)) -> (c -> a, c -> b)            -- the other direction
fork h = (fst . h, snd . h)
swap :: (a, b) -> (b, a)
swap (x, y) = (y, x)
assoc :: ((a, b), c) -> (a, (b, c))
assoc ((a, b), c) = (a, (b, c))
runit :: (a, ()) -> a
runit (a, _) = a
bimap :: (a -> a') -> (b -> b') -> (a, b) -> (a', b')
bimap f g (a, b) = (f a, g b)