123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382 |
- ..
- ::
- {-# OPTIONS --allow-unsolved-metas #-}
- module language.generalization-of-declared-variables where
- open import Agda.Primitive
- open import Agda.Builtin.Equality
- open import Agda.Builtin.Nat
- open import Agda.Builtin.Bool
- .. _generalization-of-declared-variables:
- ************************************
- Generalization of Declared Variables
- ************************************
- .. contents::
- :depth: 1
- :local:
- Overview
- ~~~~~~~~
- Since version 2.6.0, Agda supports implicit generalization over variables in types.
- Variables to be generalized over must be declared with their types in a ``variable``
- block. For example:
- ::
- variable
- ℓ : Level
- n m : Nat
- data Vec (A : Set ℓ) : Nat → Set ℓ where
- [] : Vec A 0
- _∷_ : A → Vec A n → Vec A (suc n)
- Here the parameter ``ℓ`` and the ``n`` in the type of ``_∷_`` are not bound explicitly,
- but since they are declared as generalizable variables, bindings for them are inserted
- automatically. The level ``ℓ`` is added as a parameter to the datatype and ``n`` is added
- as an argument to ``_∷_``. The resulting declaration is
- .. code-block:: agda
- data Vec {ℓ : Level} (A : Set ℓ) : Nat → Set ℓ where
- [] : Vec A 0
- _∷_ : {n : Nat} → A → Vec A n → Vec A (suc n)
- See `Placement of generalized bindings`_ below for more details on where bindings
- are inserted.
- Variables are generalized in top-level type signatures, module telescopes, and record
- and datatype parameter telescopes.
- Issues related to this feature are marked with
- `generalize <https://github.com/agda/agda/labels/generalize>`_ in the issue
- tracker.
- Nested generalization
- ~~~~~~~~~~~~~~~~~~~~~
- ..
- ::
- module _ where
- When generalizing a variable, any generalizable variables in its type are also generalized
- over. For instance, you can declare ``A`` to be a type at some level ``ℓ`` as
- ::
- variable
- A : Set ℓ
- Now if ``A`` is mentioned in a type, the level ``ℓ`` will also be generalized over::
- -- id : {A.ℓ : Level} {A : Set ℓ} → A → A
- id : A → A
- id x = x
- The nesting can be arbitrarily deep, so
- ::
- variable
- x : A
- refl′ : x ≡ x
- refl′ = refl
- expands to
- .. code-block:: agda
- refl′ : {x.A.ℓ : Level} {x.A : Set x.A.ℓ} {x : x.A} → x ≡ x
- See `Naming of nested variables`_ below for how the names are chosen.
- Nested variables are not necessarily generalized over. In this example, if the universe
- level of ``A`` is fixed there is nothing to generalize::
- postulate
- -- pure : {A : Set} {F : Set → Set} → A → F A
- pure : {F : Set → Set} → A → F A
- See `Generalization over unsolved metavariables`_ for more details.
- .. note::
- Nested generalized variables are local to each variable, so if you declare
- ::
- variable
- B : Set ℓ
- then ``A`` and ``B`` can still be generalized at different levels. For instance,
- ::
- -- _$_ : {A.ℓ : Level} {A : Set A.ℓ} {B.ℓ : Level} {B : Set B.ℓ} → (A → B) → A → B
- _$_ : (A → B) → A → B
- f $ x = f x
- Generalization over unsolved metavariables
- ------------------------------------------
- Generalization over nested variables is implemented by creating a metavariable for each
- nested variable and generalize over any such meta that is still unsolved after type
- checking. This is what makes the ``pure`` example from the previous section work: the
- metavariable created for ``ℓ`` is solved to level 0 and is thus not generalized over.
- A typical case where this happens is when you have dependencies between different nested
- variables. For instance::
- postulate
- Con : Set
- variable
- Γ Δ Θ : Con
- postulate
- Sub : Con → Con → Set
- idS : Sub Γ Γ
- _∘_ : Sub Γ Δ → Sub Δ Θ → Sub Γ Θ
- variable
- δ σ γ : Sub Γ Δ
- postulate
- assoc : δ ∘ (σ ∘ γ) ≡ (δ ∘ σ) ∘ γ
- In the type of ``assoc`` each substitution gets two nested variable metas for their contexts,
- but the type of ``_∘_`` requires the contexts of its arguments to match up, so some of
- these metavariables are solved. The resulting type is
- .. code-block:: agda
- assoc : {δ.Γ δ.Δ : Con} {δ : Sub δ.Γ δ.Δ} {σ.Δ : Con} {σ : Sub δ.Δ σ.Δ}
- {γ.Δ : Con} {γ : Sub σ.Δ γ.Δ} → (δ ∘ (σ ∘ γ)) ≡ ((δ ∘ σ) ∘ γ)
- where we can see from the names that ``σ.Γ`` was unified with ``δ.Δ`` and ``γ.Γ`` with
- ``σ.Δ``. In general, when unifying two metavariables the "youngest" one is eliminated which
- is why ``δ.Δ`` and ``σ.Δ`` are the ones that remain in the type.
- If a metavariable for a nested generalizable variable is partially solved, the left-over
- metas are generalized over. For instance,
- ..
- ::
- sum : Vec Nat n → Nat
- sum [] = 0
- sum (x ∷ xs) = x + sum xs
- ::
- variable
- xs : Vec A n
- head : Vec A (suc n) → A
- head (x ∷ _) = x
- -- lemma : {xs.n.1 : Nat} {xs : Vec Nat (suc xs.n.1)} → head xs ≡ 1 → (0 < sum xs) ≡ true
- lemma : head xs ≡ 1 → (0 < sum xs) ≡ true
- ..
- ::
- lemma {xs = x ∷ _} refl = refl
- In the type of ``lemma`` a metavariable is created for the length of ``xs``, which
- the application ``head xs`` refines to ``suc _n``, for some new metavariable ``_n``.
- Since there are no further constraints on ``_n``, it's generalized over, creating the
- type given in the comment. See :ref:`Naming of nested variables
- <naming-of-nested-variables>` below for how the name ``xs.n.1`` is chosen.
- .. _note-free-metas:
- .. note::
- Only metavariables originating from nested variables are generalized over. An exception
- to this is in ``variable`` blocks where all unsolved metas are turned into nested variables.
- This means writing
- .. code-block:: agda
- variable
- A : Set _
- is equivalent to ``A : Set ℓ`` up to naming of the nested variable (see below).
- .. _naming-of-nested-variables:
- Naming of nested variables
- --------------------------
- The general naming scheme for nested generalized variables is
- ``parentVar.nestedVar``. So, in the case of the identity function
- ``id : A → A`` expanding to
- .. code-block:: agda
- id : {A.ℓ : Level} {A : Set ℓ} → A → A
- the name of the level variable is ``A.ℓ`` since the name of the nested variable is
- ``ℓ`` and its parent is the named variable ``A``. For multiple levels of nesting the
- parent can be another nested variable as in the ``refl′`` case above
- .. code-block:: agda
- refl′ : {x.A.ℓ : Level} {x.A : Set x.A.ℓ} {x : x.A} → x ≡ x
- If a nested generalizable variable is solved with a term containing
- further metas, these are generalized over as explained in the ``lemma`` example
- above. The names of the new variables are of the form ``parentName.i`` where
- ``parentName`` is the name of the solved variable and ``i`` numbers the metas,
- starting from 1, in the order they appear in the solution.
- If a variable comes from a free unsolved metavariable in a ``variable`` block
- (see `this note <note-free-metas_>`_), its name is chosen as follows:
- - If it is a labelled argument to a function, the label is used as the name,
- - otherwise the name is its left-to-right index (starting at 1) in the list of unnamed
- variables in the type.
- It is then given a hierarchical name based on the named variable whose type it occurs
- in. For example,
- ::
- postulate
- V : (A : Set) → Nat → Set
- P : V A n → Set
- variable
- v : V _ _
- postulate
- thm : P v
- Here there are two unnamed variables in the type of ``v``, namely the two arguments to ``V``.
- The first argument has the label ``A`` in the definition of ``V``, so this variable gets the name
- ``v.A``. The second argument has no label and thus gets the name ``v.2`` since it is the second
- unnamed variable in the type of ``v``.
- If the variable comes from a partially instantiated nested variable the name of the metavariable
- is used unqualified.
- .. note::
- Currently it is not allowed to use hierarchical names when giving parameters
- to functions, see `Issue #3208 <issue-3280_>`_.
- .. _issue-3280: https://github.com/agda/agda/issues/3280
- Placement of generalized bindings
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The following rules are used to place generalized variables:
- - Generalized variables are placed at the front of the type signature or telescope.
- - Type signatures appearing inside other type signatures, for instance in let bindings or
- dependent function arguments are not generalized. Instead any generalizable variables
- in such types are generalized over in the parent signature.
- - Variables mentioned eariler are placed before variables mentioned later, where
- nested variables count as being mentioned together with their parent.
- .. note::
- This means that an implicitly quantified variable cannot depend on an explicitly
- quantified one. See `Issue #3352 <https://github.com/agda/agda/issues/3352>`_ for
- the feature request to lift this restriction.
- Indexed datatypes
- -----------------
- When generalizing datatype parameters and indicies a variable is turned into
- an index if it is only mentioned in indices and into a parameter otherwise.
- For instance,
- ..
- ::
- module Vectors where
- ::
- data All (P : A → Set) : Vec A n → Set where
- [] : All P []
- _∷_ : P x → All P xs → All P (x ∷ xs)
- Here ``A`` is generalized as a parameter and ``n`` as an index. That is, the
- resulting signature is
- .. code-block:: agda
- data All {A : Set} (P : A → Set) : {n : Nat} → Vec A n → Set where
- Instance and irrelevant variables
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Generalized variables are introduced as implicit arguments by default, but this can be
- changed to :ref:`instance arguments <instance-arguments>` or
- :ref:`irrelevant arguments <irrelevance>` by annotating the declaration of the variable::
- record Eq (A : Set) : Set where
- field eq : A → A → Bool
- variable
- {{EqA}} : Eq A -- generalized as an instance argument
- .ignore : A -- generalized as an irrelevant (implicit) argument
- Variables are never generalized as explicit arguments.
- Importing and exporting variables
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Generalizable variables are treated in the same way as other declared symbols
- (functions, datatypes, etc) and use the same mechanisms for importing and exporting
- between modules. This means that unless marked ``private`` they are exported from a
- module.
- Interaction
- ~~~~~~~~~~~
- When developing types interactively, generalizable variables can be used in holes if
- they have already been generalized, but it is not possible to introduce `new`
- generalizations interactively. For instance,
- ..
- ::
- map : (A → B) → Vec A n → Vec B n
- map f [] = []
- map f (x ∷ xs) = f x ∷ map f xs
- ::
- works : (A → B) → Vec A n → Vec B {!n!}
- fails : (A → B) → Vec A {!n!} → Vec B {!n!}
- ..
- ::
- works = map
- fails = map
- In ``works`` you can give ``n`` in the hole, since a binding for ``n`` has been introduced
- by its occurrence in the argument vector. In ``fails`` on the other hand, there is no reference
- to ``n`` so neither hole can be filled interactively.
- Modalities
- ~~~~~~~~~~
- One can give a modality when declaring a generalizable variable:
- ::
- variable
- @0 o : Nat
- In the generalization process generalizable variables get the modality
- that they are declared with, whereas other variables always get the
- default modality.
|