Alexander Kuklev, JetBrains Research
We propose (a sketch of) an extension HOTTReedy of the Higher Observational Type Theory by a first-class notion of Reedy categories and inductive type families indexed over them. HOTTReedy provides dependent session types, simplicial types and other Reedy presheafs without reccuring to any kind of non-univalent equality.
Purely inductive type families indexed and fibered over simultaneously defined Reedy categories correspond precisely to bidirectional presentations of dependent type theories, which allows developing natural functorial semantics for such theories in strong analogy with functorial semantics of algebraic theories. This justifies viewing type-theoretic presentations of weak ω-categories and virtual equipments as algebraic definitions.
Further extending the theory by parametric quantifiers and a universe of computationally-irrelevant propositions, we obtain what could be called higher observational construction calculus (HOCC). This combination enables flawless handling of higher categorical objects and naturally occuring large categories.
This work heavily builds upon (mostly unpublished) ideas of C. McBride.
The term Construction Calculi employed in the title of this paper refers to type theories that are intended to serve as general purpose structuralist foundations of mathematics. At times we will also mention type theories not striving to serve as general purpose foundational frameworks, these will be referred to as domain-specific type theories.
Construction calculi must be able to express typed higher-order intuitionistic logic including proofs, formal axiomatic theories (such as Eucledian geometry) together with formal constructions on them, and, last but not least, canonical mathematical objects such as natural and (analytic) real numers, lists, sequences, functions, relations, etc. Such canonical objects are introduced there as inductive types.
In type theory, inductive types are the types freely generated by a set of possibly recursive generators:
#Inductive Nat
0 : Nat
(_') : Nat → Nat
Here, the type Nat
is introduced as the type freely generated by one non-recursive generator 0
satisfying
type Nat
and a recursive generator (_')
(writen as a postifx apostrophe) satisfying type Nat → Nat
.
With this definition, the set of possible Nat-values is given by
0, 0', 0'', 0''', ...
The symbols 0
and (_')
do not refer to some predefined entities, they are introduced right here as generators
of the type Nat
. They represent nothing other than themselves and are irreducible. There is nothing else happening
“behind the schenes” - this definition of natural numers is entirely self sufficient.
Inductive types may be polymorphic, i.e. have typal parameters (enclosed in square brackets):
#Inductive List[\T]
Empty : List[T]
(::) : T → (List[T] → List[T])
This definition introduces the polymorphic type List[T]
parametrized by the type T
of its elements.
The backslash in \T
in the first line is the so-called freshness marker, it is there to express that T
is not a constant that was defined somewhere else, but a variable being introduced at this very spot.
The second line introduces a rather boring generator Empty
of List[T]
, much like 0 in the definition
of Nat
. The third line introduces an infix operator ::
, which is a family of recursive generators:
For each inhabitant \head : T
it defines a recursive generator
(head ::) : List[T] → List[T]
that appends head
to the right hand side argument \tail : List[T]
so that non-empty lists can be
generated by succesively appending elements to the Empty
list. Note, that the arrow operator is
right-associating, so T → (List[T] → List[T])
can be written simply as T → List[T] → List[T]
.
The Empty
together with the infix operator ::
defines the following set of possible values of List[T]
:
Empty, x :: Empty, x :: y :: Empty, x :: y :: z :: Empty, ...
for x, y, z, ...
being of type T
.
There is also a notion of inductive type family indexed over an other inductive type. For example, consider the type family of vectors of fixed length:
#Inductive Vec[\T] : Nat → *
Empty : Vec[T](0)
(::) : T → Vec[T](\n) → Vec[T](n')
Here Vec[\T]
is not one type, but a whole family of types, one for each natural number n
.
The “type” Nat → *
of Vec[T]
means “a function mapping natural numbers to types“ modulo issues stemming from
the fact that the class of all types *
is not really a type itself and requires somewhat careful handling to avoid
running into the barber issues.
The generator Empty
satisfies the type Vec[T](0)
, vector of T
s of zero length.
Generators (head ::)
take a vector \tail : Vec[T](\n)
of some length \n
(notice the
freshness marker) and generate a vector of length n' = n + 1
.
In this work, we propose to introduce inductive types indexed over more general entities than
inductive types themselves. We will call these entities index types. Index types are inductive types
endowed with a (correct by construction, inductively generated) structure of a Reedy category
with connections.
We built upon an unpublished idea of Conor McBride presented in his Topos Institute Lecture
“Cats and Types: Best Friends?“. The inductive type famlies of
the kind I → *
for an index I
will semantically correspond to type-valued presheaves on
I
as Reedy category.
Using this notion, we will be able to construct various very useful indices:
[\C : CatCarrier → *] ≡ [\Ob : *, \Mor : Ob → Ob → *]
;nCatCarrier[n]
so that
[\C : CatCarrier → *] ≡ [
\C.Cell(0) : *
\C.Cell(1) : Ob → Ob → *
\C.Cell(2) : ···
...
\C.Cell(n) : ···
]
allowing to define n-categories and n-functors between them generically for all n.
Δ⁺ → *
and Δ → *
will correspond
precisely to semi-simplicial and simplicial types respectively, which allows to define ω-categories and
various other interesting structures. In particular, one covers the notion of very-dependent types as
introduced by Jason J. Hickey and A. Kopylov, cf. “Formal objects in type theory using very dependent
types.”.Before proceeding to our contributions let us breefly chart the landscape of types and principles of Construction Calculi. This overview should be skipped by readers versed in type theory.
The introduction only mentions inductive types. These are used in construction calculi to represent canonical mathematical objects such as natural numbers, real numbers, various combinatorial objects (e.g. graphs), and finitary collections of objects of known type, e.g. pairs of integers, couples (unordered pairs) of rationals, (finite) lists of reals, etc. Inductive types are “built from below”, i.e. it is exactly knows what their values are and how are they built from ground up.
However, inductive types are insufficient to describe everything of mathematical interest; one also needs the dual notion of behavioral types.
Behavioural types are described not in terms of generators, but in terms of extractors. For behavioral types one remains completely agnostic about nature of their values as long as they provide a given “interface“. Consider the type of possibly infinite streams:
#Structure Stream[\T]
head : T
tail : Maybe[ Stream[T] ]
where
#Inductive Maybe[\T]
Nothing : Maybe[T]
Value(t : T) : Maybe[T]
Here the inhabitants of the type Stream[T]
are defined as values with distinguished extractors head
, yielding
a value of the type T
, and tail
yielding either the rest of the stream or the value Nothing
if the stream
ends there.
Values of behavioural types can be defined by specifying actions of their extractors (recursion is allowed). To give an example, let us define the Fibonacci sequence. Fibonacci sequence is a sequence, in which each number is the sum of the two preceding ones. A Fibonacci sequence can be defined for any two initial elements, while the Fibonacci sequence is a Fibonaccy sequence starting with 0 and 1:
(0,) 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, ...
Here is how to define them:
#Defintion fibonacci-sequence(\current \previous : Nat) : Stream[Nat]
head ↦ current
tail ↦ fibonacci-sequence((current + previous), current)
#Default the-fibonacci-sequence
fibonacci-sequence(1, 0)
The fibonacci-sequence(n, m)
yields n
when asked for a head
and fibonacci-sequence(n + m, n)
when asked for
a tail.
In contrast to values of purely inductive types (which are exhausted by ones that can be explicitly written down),
a value s : Stream[Nat]
might be a thing “living outside of the computer” being “measured” by head
and
tail
: it can be shown constructively that the type Stream[Nat]
is not exhausted by values that can be written
down inside the theory: the type of Nat
-streams is uncountably infinite. Note that equality of two streams
s g : Stream[Nat]
cannot be in general verified in finite time. Verifying such equality would in general require
checking equality for an infinite number of terms.
Functions f : X → Y
can be seen as a trivial case of behavioral types: behavioral types with a family
of non-recursive extractors parametrized by values x : X
:
#Structure Function[\X \Y]
apply : X → Y
While it is customary in computer science to use the word “function” for partial functions (that might sometimes fail to yield a result), in mathematics and type theories by “functions” one means total and deterministic functions.
That’s how one defines a function on Nat
:
#Define double : Nat → Nat
0 ↦ 0
(\n)' ↦ ( double(n) )''
Functions on inductive types can be defined by exhaustive pattern matching on their generators. In case of recursive
generators, definitions are allowed to be inductive. In the above example one performs an exhaustive pattern matching
on natural numbers: natural number is either a zero 0
, or a successor n'
of a natural number n
. Thus one
defines the value of the function double
case by case first for zero 0
and then for successor n'
, in the latter
case the value double(n)
is already “known”. The ability to define functions (terminating, total functions) on
inductive types by pattern matching on their generators reflects the defining property of inductive types: their
values are guaranteed to be finitary compositions of their generators.
Types are not either inductive or behavioral, but can be mixed. For example the types List[ Stream[Nat] ]
and
Maybe[Nat → Nat]
are not purely inductive any more. Now let us define purely inductive types because of their
remarkable properties.
§Definition
Purely inductive types are inductive types that either a finite number of generators (like Nat
) or
only generator families parametrized by other purely inductive types. For example, the types Nat
,
List[Nat]
and List[List[Nat]]
are purely inductive, while the type List[Nat → Nat]
is not pure.
From within the type theory purely inductive types can be shown to be either finite, or countably infinite,
that is, their values can be explicitly numbered by natural numbers n : Nat
in one-to-one fasion.
Equality of values of purely inductive types is decidable, that is checkable algorithmically in finite number
of steps.
Metatheoretically, that is from outside of the respective type theory, one strives to show two desirable
computational properties of the type theory: normalization and canonicity. Normalization means that any
expression of the type T
eventually reduces to the normal form, while canonicity means that for purely
inductive types T
the only normal forms in empty context are given by finite compositions of respective
generators.
Consider the degenerate inductive type
#Inductive Empty : *
/- no constructors -/
This type has no constructors, and in a type theory enjoing normalization and canonicity there can be no expressions
of the type Empty
in empty context. At the same time, a function on this type can be defined (as it is the case
for all inductive types) by pattern matching. Yet there are no constructors to match, such function has no body
and still exists. In fact there is a unique function from Empty
to any type X
. Fortunatelly in cannot be ever
applied because the type Empty
has no inhabitants.
In Construction Calculi logical propositions are represented by types inhabited by proofs of respective
propositions. A function P → Q
between two propositions by definition turns proofs of P
into proofs of Q
and
therefore is a proof that P
implies Q
. The type Empty
encodes the canonical false proposition: it has no
proofs and if there were any proofs, (remember, there is a function form Empty
into any type X
) it would allow
prove all propositions P
(together with their negations ¬P
, because they are propositions as well) therefore
trivializing the theory, which is known in logics as “ex falso quodlibet”. By the way, negation of an arbitrary
proposition P
can be defined as P → Empty
(P
is false exactly we we can derive contradiction by assuming it
to be true).
All provably false propositions can be shown to be equivalent to Empty
. One direction (X -> Empty
) comes from
the definition of negation, the other direction (Empty -> X
) comes from the fact that there is a function from
Empty
into any type. The same way, any true propoistion can be shown to be equivalent to the type Unit
with
exactly one element. Yet, one cannot show constructively that the class of all propositions Ω
is exhausted by this
two variants: besides provably false propositions and provably true ones there can be unsettled ones. To give a
concrete example, existance of sets strictly larger than the set of natural numbers and strictly smaller than the
set of natural number sequences is an example of such an unsettled proposition in the standard set theory. It is known
as Continuum Hypothesis. Existence of such sets are neither implied nor ruled out by axioms of the set theory.
There are models of set theory without such sets and there are other perfectly valid models where such sets exist.
Futhermore, one cannot settle all propostions by adding more axioms. Gödel’s incompleteness theorem states that any
axiomatic theory (with finitely generated system of axioms) has unsettled propositions at least if is powerful enough
to express natural numbers and multiplication on them as an operation.
While all true propoistions are alike and all false propositions are alike, unsettled propositions are unsettled in
their own way. It might be that one unsettled proposition is implied by another (e.g. Generalized Continuum
Hypothesis implies the Continuum Hypothesis, yet both are independent of standard set theory), or they can be
completely independent. Constructively, the class of all propositions Ω
is bounded lattice ordered by implication
P → Q
with bottom element Empty
(the false proposition) and top element Unit
(the true proposition).
The “class” of canonical propositions Ω
is seen a as a type in most Construction Calculi. It is neither an
inductive type, nor a behavioural one, and its inhabitants are themselves types (propositions are considered
to be types inhabited by their respective proofs). Such types (types of types) are known as universes and form
a third large group of types besides inductive and behavioral ones.
For any type X
there is a proposition “X
is non-empty” that we’ll denote ⁰X : Ω
.
As it was already mentioned, the class of canonical propositions Ω
contains Empty
and Unit
and is closed
under forming functions: for P Q : Ω
, (P → Q) : Ω
. It is also closed under forming pairs: a pair of proofs,
one for P
and one for Q
is precisely the proof of P ‹and› Q
. Via implication and negation one can also define
the logical conjunction (‹or›)
. Together with these two logical conjunctions the type Ω
forms a Heyting algebra,
moreover a complete one as we will see in the next section.
All constructive calculi of concern are compatible with axiom of double negation elimination ¬¬P → P
that
trivializes all structure mentioned above to classical logic where every proposition has a definite truth value
true
or false
, yet this axiom is not derivable constructively in general. Double negation elimination can be
derived constructivly only for a very narrow class of propositions: namely, for decidable ones (these are the ones
that can be at least in theory checked algorithmically).
By means of indexed inductive types one can define predicates on inductive types:
#Inductive (_-is-even) : Nat → Ω
zero-is-even : (0)-is even
suc-of-suc-is-even(\n : Nat) : (n)-is even → (n'')-is even
Here, the predicate -is-even
on natural numbers is defined. Equivalently, for each natural number n
a type (n)-is-even
is defined, which can be either empty (which stands for false) or have an inhabitant
(which stands for true). Here the generator zero-is-even
populates (0)-is even
, and the generator
suc-of-suc-is-even(\n : Nat)
populates (n + 2)-is even
whenever (n)-is even
.
While this particular predicate is decidable (one can easily check if a given number is even), in general inductively defined predicates are not. For example it is still unknown (cf. Collatz conjecture) if the following predicate is decidable:
#Inductive Collatz-Terminating : Nat → Ω
ct-zero : Collatz-Terminating(0)
ct-one : Collatz-Terminating(1)
ct-half(\n) : Collatz-Terminating(n) → Collatz-Terminating(2 · n)
ct-triple-plus-one(\n) : Collatz-Terminating(3 · n + 1) → Collatz-Terminating(n)
In dependent type theories there are so called dependent function types:
For a type X
and an inductive type family Y : X -> *
indexed over it, there is a type
∀(\x : X) Y(x)
, read “for each x
of X
a value of the type Y(x)
”. For example the function
f : ∀(\n : Nat) Vec[Nat](n)
must yield a vector of length n
for each number n
.
When applied to predicates, dependent functions reassemble universal quantifier. The type
∀(\n : Nat) Collatz-Terminating(n)
is populated precisely by functions yielding a proof of Collatz-Terminating(n)
for each n
,
that is precisely by constructive proofs of the proposition ∀(\n : Nat) Collatz-Terminating(n)
.
To give an example how such proofs might look like consider an easier proposition:
∀(\n : Nat) ( double(n) )-is-even
Functions are defined by pattern matching, and we are allowed to unfold the definition of double
while matching:
#Define prf : ∀(\n : Nat) ( double(n) )-is-even
0 ↦ zero-is-even : ( double(0) )-is-even
(\n)' ↦ suc-of-suc-is-even( double(n) )(prf(n) : ( double(n) )-is-even) : ( double(n') )-is-even
The class of all propositions Ω
is closed under forming arbitrary conjunctions:
For any family of propositions P : X → Ω
one can form ∀(\x : X) P(x) : Ω
, which means Ω is a complete Heyting
algebra. Since Ω
a complete Heyting algebra and contains any proposition definable within HOCC, subsets of any type
T
can be identified with predicates P : T → Ω
. In fact, we can even introduce special syntax for subset types
{\t : T | P(t)}
, for example {\n : Nat | (n)-is-even ‹and› (10 ≤ n) }
.
Relations on a type can be defined as twice indexed inductive types:
#Inductive (≤) : Nat → Nat → Ω
≤-refl(\n) : (n ≤ n)
≤-succ(\n \m) : (n ≤ m) → (n ≤ m')
Each inductive type automatically comes with an indictively defined equality relation that exactly follows the pattern of its generators. For example, for the type of natural numbers the equality relation can be given as:
#Inductive (=) : Nat → Nat → Ω
0= : (0 = 0)
(\n)'= : (n' = n')
For behavioral types, equality follows the pattern of their extractors and represents observational equivalence,
that is two “things” are equal precisely if applying same extractors yields same values. In particular, for two
functions \f \g : X → Y
the equality is given by
pointwise : ∀(\x : X) f(x) = f(y)
In particular, in type theory two implementations of the same function are considered equal as functions if they yield equal results on equal arguments.
§ Index types ————-
As we’ve seen, some inductive types have only finite number of generators (like Nat
) while some have
generator families (like (head ::) : List[T] → List[T]
) that can be infinite, possibly even uncountably infinite.
Purely inductive types are inductive types that either a finite number of generators (like Nat
) or only generator
families parametrized by other purely inductive types. For example, the types Nat
, List[Nat]
and List[List[Nat]]
are purely inductive, while the type List[Nat → Nat]
is not pure.
Purely inductive types have decidable equality and either finite or countably infinite. As types with decidable
equality, they satisfy the UIP-condition ∀(a b : T) ∀(e o : a = b) e = o
, which is known as Hedberg’s theorem.
[UIP Dicussed above]
This property is very useful for indexes. Consider a type I
and an inductive type family
P : I -> *
indexed over it. If I
is satisfies UIP by definition, and one establishes for two its elements
\a \b : I
that \e : (a = b)
, values of \x : P(a)
uniquely correspond to values P(b)
. This correspondence is
given by operator called coerce[P](e, x) : P(b)
. Without UIP, one can show that P(a) = P(b)
and …
Purely inductive types have one more important metatheoretical propery we’ll make use of: inhabitants of each purely
inductive type are naturally ordered lexicographically, and this order is guaranteed to be well-founded. That is,
metatheoretically we have a function deg(i)
that maps inhabitants to a countable ordinal.
… несколько слов о том, зачем следующее определение
An index type I : Idx
is a purely inductive type |I|
with additional structure of inductively generated
correct-by-construction Reedy category, that is for each inhabitant \i : I
,
⬇(i)
of outbound “dependency arrows“ together with a function target : ⬇(i) → I
,
dependency arrows are required to lower degree deg(i)
of inhabitants.g : ⬇(i)
a function g^ : ⬇( target(g) )
such that application ^g(x)
and composition
^g ∘ ^x
agree definitionally. This way we ensure provide computation rules for composition of depency arrows that
are definitionally associative.⬆(i)
of inbound “inclusion arrows” together with a function source : ⬆(i) → I
.
Inclusion arrows are required to raise the degree.One type one often encounters is the type of number sequences containing only finite number of nonzero terms.
For many practical applications one needs to have an upper bound on the number of nonzero entries, because it
cannot be calculated in predictable time if unknown even in case of integer number sequences; in case of real
number sequences it is not computable at all since the check an unknown decimal fraction represents a zero
requires an infinite number of steps. So we need an inductive type family
FiniteVec[\T : *, \zero : T] : NatBound → *
of sequences parametrized by the type T
of its terms, marked
zero : T
element of that type and indexed over an upper bound to a number of non-zero terms.
The index NatBound
ist not just a natural number. We want FiniteVec[T,0][n]
to be a subtype of
FiniteVec[T,0][m]
whenever n < m
and we want trailing zeroes to be ignored, i.e. sequences (x :: y :: z)
and (x :: y :: z :: 0)
to be equal.
WARNING: THE REST OF THIS SECTION HAS TO BE REWRITTEN AFTER THE PREVIOUS SECTION HAS BEEN COMPLETED
Simple mathematical structures are defined above a carrier which is simply a type:
#Structure Monoid[\T : *]
unit : T
(∘) : T → T → T
associator(\x \y \z : T)
: (x ∘ y) ∘ z = x ∘ (y ∘ z)
lt-unitor(\x : T) :
: unit ∘ x = x
rt-unitor(\x : T) :
: x ∘ unit = x
More advanced mathematical structures seem not to have a single carrier:
#Structure Cat[\Ob : *, \Mor : Ob → Ob → *]
id[\T] : T
(∘)[\A \B \C] : Mor[B][C] → Mor[A][B] → Mor[A][C]
lt-unitor[\A \B](\f : Mor[A][B]) :
: id[A] ∘ f = f
rt-unitor[\A \B](\f : Mor[A][B]) :
: f ∘ unit = f
associator[\A \B \C \D](\f : Mor[A][B], \g : Mor[B][C], \h : Mor[C][D])
: (h ∘ g) ∘ f = h ∘ (g ∘ f)
For a multitude of reasons it is desirable to represent the whole parameter
list [\Ob : *, \Mor : Ob → Ob → *]
as a single carrier [C : CatCarrier → *]
.
For this purpose we’ll need an index type CatCarrier
with dependency arrows:
#Index CatCarrier:
Ob : CatCarrier
Mor : CatCarrier
Mor [Src⟩ Ob
Mor [Tgt⟩ Ob
Dependency arrows are exactly the same as embedding arrows except that they comply with inverse lexicographic
ordering on the index, i.e. they are well-founded, all composable strings of dependency arrows are finite.
It is precisely this finiteness that allows us introduce a special restriction operator (↾): any indexed
typeformer T : I → *
and index \i : I
the restriction (T ↾ i) denotes a dependent record type:
its extractors are given by dependency arrows form i
and map to their respective types as given by T
and
previous entries of the dependent record. Now given an indexed typeformer T : I → *
we have T(i) : (T ↾ i) → *
.
For indices with no dependent arrows, (T ↾ i) is the unit type, thus one has simply T(i) : *
.
In particular, given a typeformer T : CatCarrier → *
, we have
T.Ob : *
T.Mor : (T ↾ Mor) → *
⇕
T.Mor : {src : Ob, tgt : Ob} → *
Here is how one defines and an inductive type indexed by CatCarrier:
#Inductive SmallPointedTypes[\I : CatCarrier]
PointedType(\T : 𝒰, \p : T) : SmallPointedTypes[Ob]
PointedFunction(\X \Y : 𝒰, \x : X, \y : Y, f : (X → Y), pointedness : ( f(x) = y ))
: SmallPointedTypes[Mor][(Src ↦ PointedType(X, x); Tgt ↦ PointedType(Y, y)]
So far we only considered finite dependent indexes, let us consider an infinite one to illustrate the concept better.
The canonical example of an infinite index is given by Natⱽ
:
#Index Natⱽ:
0 : Natⱽ
(_') : Natⱽ → Natⱽ → Natⱽ
(\n)' [Field(\m : Fin[m])⟩ m
[Field(\m)⟩^: (_ ↦ [Field(m)⟩)
For a given T : Natⱽ → *
the restriction T ↾ n
is the dependent record
field(0) : T(0)
field(1) : T(1)[ field(0) ]
field(2) : T(2)[ field(0) ][ field(1) ]
...
field(n - 1) : T(n - 1)[ field(0) ]...[ field(n - 2) ]
Thus, T : Natⱽ → *
gives us precisely the so called very dependent types. A very-dependently typed sequence
of such type T
can be defined as follows:
#Coinductive DepSequence[\T : Natⱽ → *]
head : T(0)
tail : DepSequenceTail[T, 1, (field(0) ↦ head)]
where
#Coinductive DepSequenceTail[\T : Natⱽ → *][\i : Nat][\prefix : (T ↾ n)]:
head : T(i)[prefix]
tail : DepSequenceTail[T, i', prefix ++ (field(i) ↦ head)]
Analogously one can define the index Δ⁺, so that Δ⁺ → *
are semi-simplicial types. By combining dependencies
and degeneracies one can also define the simplicial types. In general, we’ll be able to form presheaves over any
explicitly definable Reedy-categories, and with those, we can provide definitions for any higher categorical objects.
It still remains to be worked out which additional machinery is required to work with dependencies and embeddings
properly: for example we used the operator (++)
to extend a restriction (T ↾ n)
to a restriction (T ↾ n')
.
It also remains to be worked our how to provide codes for indexes and type families indexed over them so that we can mutually define type universes and index universes closed under them, and ensure the metatheoretical property that any type of our extended system eventually lands in a sufficiently large universe.
… The example of monoidal structure on semi-simplicial category, using CAST operator
Above we used a special type definition language to define inductive types, including polymorphic and indexed ones.
As a result of type definition we obtain a typeformer (e.g. Nat
and List
) of a specific kind that looks like
a type but is not exactly a type:
Nat : *
List : * → *
Vec : * → Nat → *
Unfortunatelly, in type theory we are not allowed to have the type *
of all types, as it would necessarily
contain itself which leads to a contradiction. There is no better alternative to having an separate “type system”
of kinds for typeformers.
A type former is either a simple type, a polymorphic one (parameters might themselves be of any kind), or an indexed one therefore valid typeformer kind is given by:
*
index → kind
kind → kind
Here the signatures on the right hand side may depend on paramerers on the left hand side, and any normal type can be used as an index. Here are some examples of valid signatures:
*
Nat → *
* → *
* → (Δ⁺ → *)
(\T : *) → Monoid[T] → *
While we cannot speak about the type of all types, one can very well speak about types containing some other
types without pretending to contain all of them. Such types are called type universes.
In particular, HOCC we postulate a distinghished type universe Prop
that contains an isomorphic copy of each
type P
satisfying ∀(\x y\ : P) x = y
, it is each type with at most one element. Subsets of any type T
have
the form {\x : T | P(x)}
for some P : T → Prop
, i.e. the type (T → Prop)
can be said to classify subsets of
any type T
. The universe Prop
is said to be subset (or subobject) classifier. They type Prop
has at least
two distinct elements: the empty type 𝟘 and the unit type 𝟙 (the type with the unique inhabitant denoted • : 𝟙
),
and thus does not belong to itself.
For each universe 𝒰
we define 𝒰⁺
to be the universe containing
1) all inhabitants of 𝒰
,
2) the type 𝒰
itself
and is closed under
3) forming a certain class† of inductive types, including dependent pairs Σ(\x : X) Y(x)
for X Y(_) : 𝒰⁺
,
4) forming a certain class† of behavioral types, including dependent functions ∀(\x : X) Y(x)
for X Y(_) : 𝒰⁺
,
5) forming types of identifications (a = b)
between inhabitants a b : T
of their types T : 𝒰
.
Now one can generate a cumulative hierarchy of universes
Prop ⊂ Prop⁺ ⊂ Prop⁺⁺ ⊂ ···
The universe Prop⁺ and all higher universes in this hierarchy taken together with maps between their types as
categories are in fact elementary toposes*: (2) guarantees them to have subobject classifier, (3) guarantees them
to have a natural number object, (3 + 5) guarantees them to have all finite limits Σ(\x : X, \y : Y) f(x) = g(y)
,
(5) makes them locally cartesian closed (∀(\x : X) Y(x)
).
All purely inductive types including List[Nat]
, List[List[Nat]]
and similar much more complicated ones land
in the very first nontrivial universe Prop⁺
since they are countable and discrete by construction which makes
them isomorphic either to the type of natural numbers Nat
or to a finite type Fin(n)
which are already present
in Prop⁺
.
[Except for the principle of Unique Choice]
We can develop a system of codes for all inductive and coinductive types definable in our type definition language and adjust the closedness requirements (3) and (4), to ensure the following metatheoretic property:
For any finite number of definable typeformers, there is a universe in the above hierarhcy, that contains them/is closed under applying them.
Now we can give metatheoretic meanings to kinds of type formers:
SomeType : *
means that SomeType : 𝒰
for a sufficiently large universe 𝒰 and all universes above it.
SomeOtherType : * → *
means that SomeOtherType
acts as function 𝒰 → 𝒰
on sufficiently large universes.
In fact,
*
can be interpreted even more broadly. A polymorphic type definition makes sense not only in a universeProp⁺⁽ⁿ⁾
but in and elementary topos that includes all types mentioned in the definition of the polymorphic type being interpreted. Since (higher) topos structure is preserved by forming presheaves, any kind can be generalized by replacing a particular strictly-positive occurence of*
by(ϰ → *)
, whereϰ
is an arbitrary kind, which corresponds to transferring a construction from a universe to a presheaf valued in this universe.
After we design a system of codes for inductive and behavioral types we actually do not need separate type
definitions at all. They do not exist in the core HOCC. One can define types and type formers as usual expressions
involving generators of the types Prop⁺⁽ⁿ⁾
without referring explicitly to kinds and polymorphism. We seemingly
do not need any kinds at all, everything involves only bona fide types.
This is not entirely true: to emulate fully polymorphic typeformers (i.e. w/o restriction to a particular fixed
universe), we need lifting operators indexed by kinds. Consider the typeformer List
, which now has the bona fide
type List : 𝒰 → 𝒰
. How do we apply it to a type living in a higher universe 𝒰⁺? We need a lifting operator (↑)
that turns List : 𝒰 → 𝒰
into ↑List : 𝒰⁺ → 𝒰⁺
.
The lifting operator has four parameters besides the expression being lifted:
Lifting operator checks that the expression being lifted satisfies the type obtained by specializing ϰ to 𝒰,
and yields an expression of the type obtained by specializing η to 𝒱. The ability of lifting to replace any *
in a strictly-positive position of kind by (ϰ → *)
for any kind ϰ is precisely what we mean by “*
is more
than Type”. We’ll discuss that in depth in the section about handling categories below.
We’ve already discussed how fully polymorphic type constructors are just a syntactic sugar that can be faithfully emulated by the cummulative universe hierarchy and lifting operators. Now what about polymorphic constructions / theorems / functions / lemmas? To emulate them in full generality one needs an additional quantifier and another lifting operator.
In addition to the usual universal quantifier “for each” ∀(\x : X) Y[x]
HOCC has parametric quantifiers “for
all (independently of their values)” written as ⋂(\x : X) Y[x]
. These were introduced under various names at
least a dozen of times. In particular by Miquel as implicit dependent products, by ?? as dependent intersection
types, by C. McBride in “I Got Plenty o’ Nuttin’”.
Expressions of that type are inhabited by a special kind of lambda-abstractions:
(\x :⁰ X) expr
The superscript zero 0 reflect to the fact that x
is allowed to be used in the expr
exactly zero times not
counting usages in type annotations.
When regarding to values, the ⋂-quantifier has more of an existential flavour:
c : ⋂(\length : Nat) Vec[T][length]
means that c
is a T
-vector of some length. The length exists, that’s all we know, and it cannot be extracted.
There are not much definable expressions of the type ∀(\T : U) List[T]
. Since T
is an unknown type we cannot
excibit any of its inhabitants. In fact it might be empty. So the only definable expression of this type is
(\T : U) ↦ Empty[T]
that produces an empty list of the given type. The variable T
has only usages in type
annotations, therefore this expression also typechecks against the type ⋂(\T : U) List[T]
.
Exactly for that reason it might be tempting to think that for any universe U
the types ∀(\T : U) Y[T]
and ⋂(\T : U) Y[T]
are contain the same definable values, i.e. the type ∀(\T : U) Y[T]
can contain only
constants of the type Y[T]
. It can be shown to be false if we take Y[T]
to be U
. In this case the function
(\T : U) ↦ U
satisfies to the type ∀(\T : U) U
, but not ⋂(\T : U) U
.
Now we’re ready to state that fully polymorphic functions/lemmas (i.e. the ones where polymorphism is not restricted to a particular universe) are not a part of the core HOCC, but are emulated by functions/lemmas parametrically quantified on universes and lifting.
We’ll need a lifting operator for such functions/lemmas, that will be also signature indexed. Whenever we prove a statement
p : ⋂(\T : U) ∀(\m : Monoid[T]) something
we would be able to transport it to larger universes U’.
Working directly with polymorphic typeformers and functions/lemmas is a syntactic sugar over the core HOCC in the very same way as the von Neumann-Gödel-Bernays set-and-class theory NBG is a syntactic sugar on (conservative extension of) its core set theory ZFC. Being able to speak about polymorphic typeformers and functions / lemmas corresponds to being able to speak about classes. In particular, both provide a language to express constructions applicable to all groups, all categories and so on.
Let’s consider categories as structures of the form
#Structure Cat[\Ob : *, \Mor : Ob → Ob → *]:
id[\T : Ob] : Mor[T][T]
compose[\X \Y \Z : Ob] : Mor[X][Y] → Mor[Y][Z] → Mor[X][Y]
... axioms
As we explained in depth above, we can define an index CatCarrier
so that Cat
can be seen as a structure
endowing a carrier adhering to the signature C : CatCarrier → *
:
#Structure Cat[\C : CatCarrier → *]:
id[\T : C.Ob] : C.Mor[Src ↦ T; Tgt ↦ T]
compose[\X \Y \Z : C.Ob]
: C.Mor[Src ↦ X; Tgt ↦ Y] → C.Mor[Src ↦ Y; Tgt ↦ Z] → C.Mor[Src ↦ X; Tgt ↦ Y]
... axioms
In mathematics we frequently work with seemingly large categories of structured types, like category of all groups or
all rings. In simple categories, Mor[\src : Ob, tgt : Ob] : *
are just types, doubly indexed by Ob
. In categories
of structured objects they are parametrized by carriers and indexed by structures of their source and target:
Mor[\X \Y : *][\src : Group[X], \tgt : Group[Y]]
It looks quite monstrously, but we really can define categories of structured types without without any special gadgets:
#Structure CatOfStructuredTypes[
\Ob : * → *,
\Mor : (SrcCarrier : *) → (TgtCarrier : *)
→ (SrcStructure : S[SrcCarrier])
→ (TgtStructure : S[TgrCarrier])
→ *]
... realization
Now we could define the category of all groups as an instance of
CatOfStructuredTypes[\Ob: Group, \Mor: GroupHomomorphism]
.
If one specializes the quite complicated object to a fixed universe U
, one obtains type isomorphic to the simple
category Cat[\Ob: Σ(T : U) Group[T], \Mor : SmallGroupHomomorphism]
of U
-small groups. Thus, such complicated
objects are in the fact quite amenable to work with considering specialization and lifting.
By using indexes (CatCarrier in particular), we wrap up the quite monstrous signature of CatOfStructuredTypes
:
#Structure CatOfStructuredTypes[\С : CatCarrier → (* → *)].
In fact, with generalized (presheaf) lifting we can dispense with defining CatOfStructuredTypes
altogether.
We can just plug the typeformer of the group structure Group : * → *
into the spot where Ob : *
is required,
and the whole signature and everything else adjusts automagically. In fact we could use structures of more
complicated carriers than just a type. For instance we could define the category of all categories.. well, almost.
Because categories don’t actually form a category, they form a 2-category.
Thankfully, our approach opens the road for defining carriers of n-categories uniformly:
#Index nCatCarrier(\n : Nat)
Cell(\m : Fin[n]) : nCatCarrier
... dependency arrows
Then one can uniformoly define the n-categories themselves:
#Structure nCat[\n : Nat][\С : CatCarrier(n) → *]
... realization
so that Cat ≅ nCat[1]
. Then one can also define n-functors between n-categories
#Structure nFunctor[\n : Nat][\С : CatCarrier[n']]
... realization
so that
Cat ≅ nFunctor[1][Cell(0)]
Functor ≅ nFunctor[1][Cell(1)]
NatTrans ≅ nFunctor[1][Cell(2)]
Finally, for each n
we can define the (n + 1)-category of n-categories and (n, m)-functors between them.
#Define nCAT(\n) : nCat[n'][nFunctor[n]]
... realization
We are unaware of any other foundational framework able to handle categories that naturally. We conjecture that within this approach one would eventially be able to formalize the whole corpus of http://ncatlab.org.
Algebraic theories are very well understood. Definition of an (possibly multisorted) algebraic theory is a description of a finite-product category in terms of generators and relations, models are given by functors on that category, homomorphisms between models are given by natural transformations. Thus, models and homomorphisms between them form a category themselves.
For a single-sorted algebraic theory Alg one can always construct the purely inductive type FreeAlg[T : *]
of free algebras on the set T
of generators, and its quotients, i.e. models of Alg given in terms of
generators and relations. The FreeAlg[Fin[n]]
is guaranteed to be countable and have verifiable equality,
that is this type is the syntactic model of the theory and consists of valid exressions with variables n
in the language of the theory Alg
. The free algebra on empty set of generators is the initial object in
the category of models. This carries over to multi-sorted algebraic theories.
For every algebraic theory Alg one can define a derived theory called cosmification of Alg. One can define a notion of generalized models (and their homomorphisms) of Alg in every model of its cosmification, the notions of model homomorphism . For example, a monoid object in a multicategory. The category of models of Alg and carries structure of the cosmification of Alg and the same applies to categories of generalized models in any cosmification of Alg which is known as microcosm-macrocosm principle.
Algebraic theories as presented are uncapable of embracing such structures as categories, toposes, polycategories, higher categories and so on, while there are descriptions of those theories entirely algebraic in their spirit. There are two known generalizations of algebraic theories (essentially algebraic theories EAT and generalized algebraic theories GAT) which are almost but not completely satisfactory. EATs have very nice semantics, but depart from algebraicity, GATs are very algebraic in their nature but don’t have a straightforward functorial semantics in terms of natural structures.
We think it is possible to develop a theory of extended algebraic theories (XAT) that takes best of both worlds and embraces bidirectionally presented dependent type theories, which can be seen as descriptions of weak model categories in terms of generators and relations.
…
…
We came incredibly near to having a Construction Calculus expressive enough to accomodate not only the discrete mathematics, but also all of undergraduate mathematics, analysis, differential geometry, topology, homotopy theory, advanced algebra, algebraic geometry, and category theory, while retaining desirable foundational properties:
In the future, we hope to establish the language of this construction calculus as purely inductive type family inside of itself and bulid a hierarchy of inner models a la “The Gentle art of levitation“ by J. Chapman, P.-E. Dagand, C. McBride and P. Morris, completing the theory.
Ultimately, we would also like to provide an apparatus to work with the Axiom of Choice or its weaker versions (double negation elimination and ultrafilter lemma) in a fenced fashion, without compromising computational properties of the parts outside of the scope where a constructive taboo was involved. Possibly, it would be a subtask of a larger goal to provide support for modal extensions like the real-cohesive homotopy type theory of Mike Shulman, as embedded DSLs.
In our opinion, the next step would be to make the formal system comfortable to work with, in particular by developing machinery for ν-rules, ornaments, subtyping, and derived implicits that include SMT-assisted proof term search.
That being done, one could consider adressing linear dependent types and quantum computations, as well as generalizing inductive and behavioral types to accomodate the quantum analogon of algebraic theories, namely Partial Algebraic Theories, and develop a notion of their models over a partial field restoring the classical algebraic theories for the case of the “field with one element“ 𝔽₁.