Agda UALib ↑


This is the Overture.Preliminaries module of the Agda Universal Algebra Library.

Logical foundations

The Agda UALib is based on a type theory that is the same or very close to the one on which on which Martín Escardó’s Type Topology Agda library is based. We don’t discuss MLTT in great detail here because there are already nice and freely available resources covering the theory. (See, for example, the section of Escardó’s notes on A spartan Martin-Löf type theory, the ncatlab entry on Martin-Löf dependent type theory, or the HoTT Book.)

The objects and assumptions that form the foundation of MLTT are few. There are the primitive types (𝟘, 𝟙, and , denoting the empty type, one-element type, and natural numbers), the type formers (+, Π, Σ, Id, denoting binary sum, product, sum, and the identity type). Each of these type formers is defined by a type forming rule which specifies how that type is constructed. Lastly, we have an infinite collection of type universes (types of types) and universe variables to denote them. Following Escardó, use denote universes in the UALib by upper-case calligraphic letters from the second half of the English alphabet; to be precise, these are 𝓞, 𝓠, 𝓡, …, 𝓧, 𝓨, 𝓩.0

That’s all. There are no further axioms or logical deduction (proof derivation) rules needed for the foundation of MLTT that we take as the starting point of the Agda UALib. The logical semantics come from the propositions-as-types correspondence: propositions and predicates are represented by types and the inhabitants of these types are the proofs of the propositions and predicates. As such, proofs are constructed using the type forming rules. In other words, the type forming rules are the proof derivation rules.

To this foundation, we add certain extensionality principles when and were we need them. These will be developed as we progress. However, classical axioms such as the Axiom of Choice or the Law of the Excluded Middle are not needed and are not assumed anywhere in the library. In this sense, all theorems and proofs in the UALib are constructive (according to nlab’s definition).

A few specific instances (e.g., the proof of the Noether isomorphism theorems and Birkhoff’s HSP theorem) require certain truncation assumptions. In such cases, the theory is not predicative (according to nlab’s definition). These instances are always clearly identified.

Specifying logical foundations in Agda

An Agda program typically begins by setting some options and by importing types from existing Agda libraries. Options are specified with the OPTIONS pragma and control the way Agda behaves by, for example, specifying the logical axioms and deduction rules we wish to assume when the program is type-checked to verify its correctness. Every Agda program in the UALib begins with the following line.

{-# OPTIONS --without-K --exact-split --safe #-}

These options control certain foundational assumptions that Agda makes when type-checking the program to verify its correctness.

Note that if we wish to type-check a file that imports another file that still has some unmet proof obligations, we must replace the --safe flag with --allow-unsolved-metas, but this is never done in (publicly released versions of) the UALib.

Agda Modules

The OPTIONS pragma is usually followed by the start of a module. For example, the Overture.Preliminaries module begins with the following line.

module Overture.Preliminaries where

Sometimes we want to declare parameters that will be assumed throughout the module. For instance, when working with algebras, we often assume they come from a particular fixed signature, and this signature is something we could fix as a parameter at the start of a module. Thus we might start an anonymous submodule of the main module with a line like module _ {𝑆 : Signature 𝓞 𝓥} where. Such a module is called anonymous because an underscore _ appears in place of a module name. Agda determines where the submodule ends by indentation. This can take some getting used to, but after a short time it will feel very natural.

The main module of a file must have the same name as the file, without the .agda or .lagda file extension. The code inside the main module is not indented. Submodules are declared inside the main module and code inside these submodules must be indented to a fixed column. As long as the code is indented, Agda considers it part of the submodule. A submodule is exited as soon as a nonindented line of code appears.

Agda Universes

For the very small amount of background about type universes we require, we refer the reader to the brief section on universe-levels in the Agda documentation.

Throughout we use many of the nice tools that Martín Escardó has developed and made available in the Type Topology repository of Agda code for the Univalent Foundations of mathematics.1 The first of these is the Universes module which we import here.2

open import Universes public

Since we use the public directive, the Universes module will be available to all modules that import the present module (Overture.Preliminaries). This module declares symbols used to denote universes. As mentioned, we adopt Escardó’s convention of denoting universes by capital calligraphic letters, and most of the ones we use are already declared in the Universes module; those that are not are declared as follows.

variable 𝓞 𝓧 𝓨 𝓩 : Universe

The Universes module also provides alternative syntax for the primitive operations on universes that Agda supports. The ` ̇ operator maps a universe level 𝓤 to the type Set 𝓤, and the latter has type Set (lsuc 𝓤). The primitive Agda level lzero is renamed 𝓤₀, so 𝓤₀ ̇ is an alias for Set lzero. Thus, 𝓤 ̇ is simply an alias for Set 𝓤, and we have the typing judgment Set 𝓤 : Set (lsuc 𝓤). Finally, Set (lsuc lzero) is denoted by Set 𝓤₀ ⁺ which we (and [Escardó][]) denote by 𝓤₀ ⁺ ̇`.

The following dictionary translates between standard Agda syntax and Type Topology/UALib notation.

Agda              Type Topology/UALib
====              ===================
Level             Universe
lzero             𝓤₀
𝓤 : Level         𝓤 : Universe
Set lzero         𝓤₀ ̇
Set 𝓤             𝓤 ̇
lsuc lzero        𝓤₀ ⁺
lsuc 𝓤            𝓤 ⁺
Set (lsuc lzero)  𝓤₀ ⁺ ̇
Set (lsuc 𝓤)      𝓤 ⁺ ̇
Setω              𝓤ω

To justify the introduction of this somewhat nonstandard notation for universe levels, Escardó points out that the Agda library uses Level for universes (so what we write as 𝓤 ̇ is written Set 𝓤 in standard Agda), but in univalent mathematics the types in 𝓤 ̇ need not be sets, so the standard Agda notation can be misleading.

There will be many occasions calling for a type living in the universe that is the least upper bound of two universes, say, 𝓤 ̇ and 𝓥 ̇ . The universe 𝓤 ⊔ 𝓥 ̇ denotes this least upper bound. Here 𝓤 ⊔ 𝓥̇ is used to denote the universe level corresponding to the least upper bound of the levels 𝓤 and 𝓥, where the _⊔_ is an Agda primitive designed for precisely this purpose.

Sigma types (dependent pairs)

Given universes 𝓤 and 𝓥, a type A : 𝓤 ̇, and a type family B : A → 𝓥 ̇, the Sigma type (or dependent pair type), denoted by Σ(x ꞉ A), B x, generalizes the Cartesian product A × B by allowing the type B x of the second argument of the ordered pair (x , y) to depend on the value x of the first. That is, an inhabitant of the type Σ(x ꞉ A), B x is a pair (x , y) such that x : A and y : B x.

The dependent product type is defined in the Type Topology library. For pedagogical purposes we repeat this definition here (inside a “hidden module” so that it doesn’t conflict with the Type Topology definition that we import and use.)3

module hide-sigma where

 record Σ {𝓤 𝓥} {A : 𝓤 ̇ } (B : A  𝓥 ̇ ) : 𝓤  𝓥 ̇  where
  constructor _,_
   pr₁ : A
   pr₂ : B pr₁

 infixr 50 _,_

Agda’s default syntax for this type is Σ A (λ x → B), but we prefer the notation Σ x ꞉ A , B, which is closer to the syntax in the preceding paragraph and the notation used in the HoTT book~\cite{HoTT}, for example. Fortunately, the Type Topology library makes the preferred notation available with the following type definition and syntax declaration.

  : {𝓤 𝓥 : Universe} (A : 𝓤 ̇ ) (B : A  𝓥 ̇ )  𝓤  𝓥 ̇
  A B = Σ B

 syntax  A  x  B) = Σ x  A , B

Warning! The symbol ꞉ is not the same as : despite how similar they may appear. The correct colon in the expression Σ x ꞉ A , B above is obtained by typing \:4 in agda2-mode.

A special case of the Sigma type is the one in which the type B doesn’t depend on A. This is the usual Cartesian product, defined in Agda as follows.

 _×_ : 𝓤 ̇  𝓥 ̇  𝓤  𝓥 ̇
 A × B = Σ x  A , B

Pi types (dependent functions)

Given universes 𝓤 and 𝓥, a type X : 𝓤 ̇, and a type family Y : X → 𝓥 ̇, the Pi type (aka dependent function type) is denoted by Π(x : X), Y x and generalizes the function type X → Y by letting the type Y x of the codomain depend on the value x of the domain type. The dependent function type is defined in the Type Topology in a standard way, but for the reader’s benefit we repeat the definition here (inside a hidden module).

module hide-pi {𝓤 𝓦 : Universe} where

 Π : {A : 𝓤 ̇ } (B : A  𝓦 ̇ )  𝓤  𝓦 ̇
 Π {A} B = (x : A)  B x

  : (A : 𝓤 ̇ )(B : A  𝓦 ̇ )  𝓤  𝓦 ̇
  A B = Π B

 infixr -1 
 syntax  A  x  B) = Π x  A , B

Warning! The symbol ꞉ is not the same as :. Type the colon in Π x ꞉ A , B as \:4 in agda2-mode.

To make the syntax for Π conform to the standard notation for Pi types (or dependent function type), Escardó uses the same trick as the one used above for Sigma types.

Now that we have studied these important types, defined in the Type Topology library and repeated here for illustration purposes, let us import the original definitions with the public directive so that they are available to all modules importing Overture.Preliminaries.

open import Sigma-Type renaming (_,_ to infixr 50 _,_) public
open import MGS-MLTT using (pr₁; pr₂; _×_; ; Π; ) public

Projection notation

The definition of Σ (and thus, of ×) includes the fields pr₁ and pr₂ representing the first and second projections out of the product. Sometimes we prefer to denote these projections by ∣_∣ and ∥_∥ respectively. However, for emphasis or readability we alternate between these and the following standard notations: pr₁ and fst for the first projection, pr₂ and snd for the second. We define these alternative notations for projections out of pairs as follows.

module _ {𝓤 : Universe}{A : 𝓤 ̇ }{B : A  𝓥 ̇} where

 ∣_∣ fst : Σ B  A
  x , y  = x
 fst (x , y) = x

 ∥_∥ snd : (z : Σ B)  B (pr₁ z)
  x , y  = y
 snd (x , y) = y

Here we put the definitions inside an anonymous module, which starts with the module keyword followed by an underscore (instead of a module name). The purpose is simply to move the postulated typing judgments—the “parameters” of the module (e.g., 𝓤 : Universe)—out of the way so they don’t obfuscate the definitions inside the module.

Also note that multiple inhabitants of a single type (e.g., ∣_∣ and fst) may be declared on the same line.

0 We avoid using 𝓟 as a universe variable because in the Type Topology library 𝓟 denotes a powerset type.

1 Martín Escardó has written an outstanding set of notes entitled Introduction to Univalent Foundations of Mathematics with Agda which we highly recommend to anyone wanting more details than we provide here about MLTT and Univalent Foundations/HoTT in Agda.

2 We won’t discuss every line of the Universes.lagda file; instead we merely highlight the few lines of code from the Universes module that define the notational devices adopted throughout the UALib. For more details we refer readers to Martin Escardo’s notes.

3 To hide code from the rest of the development, we enclose it in a named module. For example, the code inside the hide-refl module will not conflict with the original definitions from the Type Topology library as long as we don’t invoke open hide-refl. It may seem odd to define something in a hidden module only to import and use an alternative definition, but we do so in order to exhibit all of the types on which the UALib depends while ensuring that this cannot be misinterpreted as a claim to originality.

↑ Overture Overture.Equality →