123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360 |
- ..
- ::
- module language.sort-system where
- open import Agda.Builtin.Unit
- .. _sort-system:
- ***********
- Sort System
- ***********
- .. _intro-sorts:
- Sorts (also known as universes) are types whose members themselves are
- again types. The fundamental sort in Agda is named ``Set`` and it
- denotes the universe of small types. But for some applications, other
- sorts are needed. This page explains the need for additional sorts and
- describes all the sorts that are used by Agda.
- ..
- ::
- module Monomorphic where
- Introduction to universes
- =========================
- Russell's paradox implies that the collection of all sets is not
- itself a set. Namely, if there were such a set ``U``, then one could
- form the subset ``A ⊆ U`` of all sets that do not contain
- themselves. Then we would have ``A ∈ A`` if and only if ``A ∉ A``, a
- contradiction.
- Likewise, Martin-Löf’s type theory had originally a rule ``Set : Set``
- but Girard showed that it is inconsistent. This result is known as
- Girard’s paradox. Hence, not every Agda type is a ``Set``. For
- example, we have
- .. code-block:: agda
- Bool : Set
- Nat : Set
- but not ``Set : Set``. However, it is often convenient for ``Set`` to
- have a type of its own, and so in Agda, it is given the type ``Set₁``:
- .. code-block:: agda
- Set : Set₁
- In many ways, expressions of type ``Set₁`` behave just like
- expressions of type ``Set``; for example, they can be used as types of
- other things. However, the elements of ``Set₁`` are potentially
- *larger*; when ``A : Set₁``, then ``A`` is sometimes called a **large
- set**. In turn, we have
- .. code-block:: agda
- Set₁ : Set₂
- Set₂ : Set₃
- and so on. A type whose elements are types is called a **sort** or a
- **universe**; Agda provides an infinite number of universes ``Set``,
- ``Set₁``, ``Set₂``, ``Set₃``, ..., each of which is an element of the
- next one. In fact, ``Set`` itself is just an abbreviation for
- ``Set₀``. The subscript ``n`` is called the **level** of the universe
- ``Setₙ``.
- .. note:: You can also write ``Set1``, ``Set2``, etc., instead of
- ``Set₁``, ``Set₂``. To enter a subscript in the Emacs mode, type
- "``\_1``".
- Universe example
- ----------------
- So why are universes useful? Because sometimes it is necessary to
- define, and prove theorems about, functions that operate not just on
- sets but on large sets. In fact, most Agda users sooner or later
- experience an error message where Agda complains that ``Set₁ !=
- Set``. These errors usually mean that a small set was used where a
- large one was expected, or vice versa.
- For example, suppose you have defined the usual datatypes for lists
- and cartesian products:
- ::
- data List (A : Set) : Set where
- [] : List A
- _::_ : A → List A → List A
- data _×_ (A B : Set) : Set where
- _,_ : A → B → A × B
- infixr 5 _::_
- infixr 4 _,_
- infixr 2 _×_
- Now suppose you would like to define an operator ``Prod`` that inputs
- a list of ``n`` sets and takes their cartesian product, like this:
- .. code-block:: agda
- Prod (A :: B :: C :: []) = A × B × C
- There is only one small problem with this definition. The type of
- ``Prod`` should be
- .. code-block:: agda
- Prod : List Set → Set
- However, the definition of ``List A`` specified that ``A`` had to be a
- ``Set``. Therefore, ``List Set`` is not a valid type. The solution is
- to define a special version of the ``List`` operator that works for
- large sets:
- ::
- data List₁ (A : Set₁) : Set₁ where
- [] : List₁ A
- _::_ : A → List₁ A → List₁ A
- With this, we can indeed define:
- ::
- Prod : List₁ Set → Set
- Prod [] = ⊤
- Prod (A :: As) = A × Prod As
- Universe polymorphism
- ---------------------
- To allow definitions of functions and datatypes that work for all
- possible universes ``Setᵢ``, Agda provides a type ``Level`` of
- universe levels and level-polymorphic universes ``Set ℓ`` where ``ℓ :
- Level``. For more information, see the page on :ref:`universe levels
- <universe-levels>`.
- Agda's sort system
- ==================
- The implementation of Agda’s sort system is closely based on the
- theory of pure type systems. The full sort system of Agda consists of
- the following sorts:
- - ``Setᵢ`` and its universe-polymorphic variant ``Set ℓ``
- - ``Propᵢ`` and its universe-polymorphic variant ``Prop ℓ``
- - ``Setωᵢ``
- Sorts ``Setᵢ`` and ``Set ℓ``
- ----------------------------
- As explained in the introduction, Agda has a hierarchy of sorts ``Setᵢ
- : Setᵢ₊₁``, where ``i`` is any concrete natural number, i.e. ``0``,
- ``1``, ``2``, ``3``, ... The sort ``Set`` is an abbreviation for
- ``Set₀``.
- You can also refer to these sorts with the alternative syntax
- ``Seti``. That means that you can also write ``Set0``, ``Set1``,
- ``Set2``, etc., instead of ``Set₀``, ``Set₁``, ``Set₂``.
- In addition, Agda supports the universe-polymorphic version ``Set ℓ``
- where ``ℓ : Level`` (see :ref:`universe levels <universe-levels>`).
- Sorts ``Propᵢ`` and ``Prop ℓ``
- ------------------------------
- In addition to the hierarchy ``Setᵢ``, Agda also supports a second
- hierarchy ``Propᵢ : Setᵢ₊₁`` (or ``Propi``) of :ref:`proof-irrelevant
- propositions <prop>`. Like ``Set``, ``Prop`` also has a
- universe-polymorphic version ``Prop ℓ`` where ``ℓ : Level``.
- .. _set-omega-plus-n:
- Sorts ``Setωᵢ``
- ---------------
- To assign a sort to types such as ``(ℓ : Level) → Set ℓ``, Agda
- further supports an additional sort ``Setω`` that stands above all
- sorts ``Setᵢ``.
- Just as for ``Set`` and ``Prop``, ``Setω`` is the lowest level at an
- infinite hierarchy ``Setωᵢ : Setωᵢ₊₁`` where ``Setω = Setω₀``. You can
- also refer to these sorts with the alternative syntax ``Setωi``. That
- means that you can also write ``Setω0``, ``Setω1``, ``Setω2``, etc.,
- instead of ``Setω₀``, ``Setω₁``, ``Setω₂``.
- Now it is allowed, for instance, to declare a datatype in ``Setω``.
- This means that ``Setω`` before the implementation of this hierarchy,
- ``Setω`` used to be a term, and there was no bigger sort that it in
- Agda. Now a type can be assigned to it, in this case, ``Setω₁``.
- However, unlike the standard hierarchy of universes ``Setᵢ``, this
- second hierarchy ``Setωᵢ`` does not support universe
- polymorphism. This means that it is not possible to quantify over
- *all* Setωᵢ at once. For example, the expression ``∀ {i} (A : Setω i)
- → A → A`` would not be a well-formed agda term. See the section
- on ``Setω`` on the page on :ref:`universe levels <set-omega>` for more
- information.
- Concerning other applications, It should not be necessary to refer to
- these sorts during normal usage of Agda, but they might be useful for
- defining :ref:`reflection-based macros <macros>`.
- .. note:: When ``--omega-in-omega`` is enabled, ``Setωᵢ`` is
- considered to be equal to ``Setω`` for all ``i`` (thus rendering
- Agda inconsistent).
- Sort metavariables and unknown sorts
- ====================================
- Under universe polymorphism, levels can be arbitrary terms, e.g., a
- level that contains free variables. Sometimes, we will have to check
- that some expression has a valid type without knowing what sort it has.
- For this reason, Agda’s internal representation of sorts implements a constructor (sort
- metavariable) representing an unknown sort. The constraint solver can
- compute these sort metavariables, just like it does when computing
- regular term metavariables.
- However, the presence of sort metavariables also means that sorts of
- other types can sometimes not be computed directly. For this reason,
- Agda's internal representation of sorts includes three additional
- constructors ``funSort``, ``univSort``, and ``piSort``. These
- constructors compute to the proper sort once enough metavariables in
- their arguments have been solved.
- .. note::
- ``funSort``, ``univSort`` and ``piSort`` are *internal* constructors
- that may be printed when evaluating a term. The user can not enter
- them, nor introduce them in agda code. All these constructors do
- not represent new sorts but instead, they compute to the right sort
- once their arguments are known.
- .. _funSort:
- funSort
- -------
- The constructor ``funSort`` computes the sort of a function type
- even if the sort of the domain and the sort of the codomain are still
- unknown.
- To understand how ``funSort`` works in general, let us assume the following
- scenario:
- * ``sA`` and ``sB`` are two (possibly different) sorts.
- * ``A : sA``, meaning that ``A`` is a type that has sort ``sA``.
- * ``B : sB``, meaning that ``B`` is a (possibly different) type that has
- sort ``sB``.
- Under these conditions, we can build the function type
- ``A → B : funSort sA sB``. This type signature means that the function type
- ``A → B`` has a (possibly unknown) but well-defined sort ``funSort sA sB``,
- specified in terms of the sorts of its domain and codomain.
- If ``sA`` and ``sB`` happen to be known, then ``funSort sA sB`` can be computed
- to a sort value. We list below all the possible computations that ``funSort``
- can perform:
- .. code-block:: agda
- funSort Setωᵢ Setωⱼ = Setωₖ (where k = max(i,j))
- funSort Setωᵢ (Set b) = Setωᵢ
- funSort Setωᵢ (Prop b) = Setωᵢ
- funSort (Set a) Setωⱼ = Setωⱼ
- funSort (Prop a) Setωⱼ = Setωⱼ
- funSort (Set a) (Set b) = Set (a ⊔ b)
- funSort (Prop a) (Set b) = Set (a ⊔ b)
- funSort (Set a) (Prop b) = Prop (a ⊔ b)
- funSort (Prop a) (Prop b) = Prop (a ⊔ b)
- Example: the sort of the function type ``∀ {A} → A → A`` with normal form
- ``{A : _5} → A → A`` evaluates to ``funSort (univSort _5) (funSort _5 _5)``
- where:
- * ``_5`` is a metavariable that represents the sort of ``A``.
- * ``funSort _5 _5`` is the sort of ``A → A``.
- .. note:: ``funSort`` can admit just two arguments, so it will be
- iterated when the function type has multiple arguments. E.g. the
- function type ``∀ {A} → A → A → A`` evaluates to ``funSort (univSort
- _5) (funSort _5 (funSort _5 _5))``
- .. _univSort: agda
- univSort
- --------
- ``univSort`` returns the successor sort of a given sort.
- Example: the sort of the function type ``∀ {A} → A`` with normal form
- ``{A : _5} → A`` evaluates to ``funSort (univSort _5) _5`` where:
- * ``univSort _5`` is the sort where the sort of ``A`` lives, ie. the
- successor level of ``_5``.
- We list below all the possible computations that ``univSort`` can perform:
- .. code-block:: agda
- univSort (Set a) = Set (lsuc a)
- univSort (Prop a) = Set (lsuc a)
- univSort Setωᵢ = Setωᵢ₊₁
- .. _piSort:
- piSort
- ------
- Similarly, ``piSort s1 s2`` is a constructor that computes the sort of
- a Π-type given the sort ``s1`` of its domain and the sort ``s2`` of its
- codomain as arguments.
- To understand how ``piSort`` works in general, we set the following scenario:
- * ``sA`` and ``sB`` are two (possibly different) sorts.
- * ``A : sA``, meaning that ``A`` is a type that has sort ``sA``.
- * ``x : A``, meaning that ``x`` has type ``A``.
- * ``B : sB``, meaning that ``B`` is a type (possibly different than ``A``) that
- has sort ``sB``.
- Under these conditions, we can build the dependent function type
- ``(x : A) → B : piSort sA (λ x → sB)``. This type signature means that the
- dependent function type ``(x : A) → B`` has a (possibly unknown) but
- well-defined sort ``piSort sA sB``, specified in terms of the element
- ``x : A`` and the sorts of its domain and codomain.
- We list below all the possible computations that ``piSort`` can perform:
- .. code-block:: agda
- piSort s1 (λ x → s2) = funSort s1 s2 (if x does not occur freely in s2)
- piSort (Set ℓ) (λ x → s2) = Setω (if x occurs rigidly in s2)
- piSort (Prop ℓ) (λ x → s2) = Setω (if x occurs rigidly in s2)
- piSort Setωᵢ (λ x → s2) = Setωᵢ (if x occurs rigidly in s2)
- With these rules, we can compute the sort of the function type ``∀ {A}
- → ∀ {B} → B → A → B`` (or more explicitly, ``{A : _9} {B : _7} → B → A
- → B``) to be ``piSort (univSort _9) (λ A → funSort (univSort _7)
- (funSort _7 (funSort _9 _7)))``
- More examples:
- * ``piSort Level (λ l → Set l)`` evaluates to ``Setω``
- * ``piSort (Set l) (λ _ → Set l')`` evaluates to ``Set (l ⊔ l')``
- * ``univSort (Set l)`` evaluates to ``Set (lsuc l)``
- * ``piSort s (λ x -> Setωi)`` evaluates to ``funSort s Setω``
|