I'm trying to understand some parts of the standard library of Agda, and I can't seem to figure out the definition of REL.
FWIW here's the definition of REL:
-- Binary relations
-- Heterogeneous binary relations
REL : ∀ {a b} → Set a → Set b → (ℓ : Level) → Set (a ⊔ b ⊔ suc ℓ)
REL A B ℓ = A → B → Set ℓ
I can't find any documentation online explaining this, which is why I'm asking here. How does this define a binary relation?
#RodrigoRibeiro's answer explains the Level bits, but once you get rid of universe levels, what does the type Set → Set → Set have to do with binary relations?
Suppose you have a binary relation R ⊆ A × B. The propositional way of modeling it is to create some indexed type R : A → B → Set such that for any a : A, b : B, R a b has inhabitants iff (a, b) ∈ R. So if you want to talk about all relations over A and B, you have to talk about all A- and B- indexed types, i.e. you have to talk about RelationOverAandB = A → B → Set.
If you then want to abstract over the relation's left- and right-hand base type, that means the choice of A and B are not fixed anymore. So you have to talk about REL, such that REL A B = A → B → Set.
What, then, is the type of REL? As we have seen from the REL A B example, it takes the choice of A and B as two arguments; and its result is the type A → B → Set.
So to summarize: given
A : Set
B : Set
we have
REL A B = A → B → Set
which itself has type Set (remember, we're ignoring universe levels here).
And thus,
REL : Set → Set → Set ∎
I guess it's easier to look at an example:
import Level
open import Relation.Binary
open import Data.Nat.Base hiding (_≤_)
data _≤_ : REL ℕ ℕ Level.zero where
z≤n : ∀ {n} -> 0 ≤ n
s≤s : ∀ {n m} -> n ≤ m -> suc n ≤ suc m
The type signature is equivalent to
data _≤_ : ℕ -> ℕ -> Set where
So _≤_ is a relation between two natural numbers. It contains all pairs of numbers such that the first number is less or equal than the second. In the same way we can write
open import Data.List.Base
data _∈_ {α} {A : Set α} : REL A (List A) Level.zero where
here : ∀ {x xs} -> x ∈ x ∷ xs
there : ∀ {x y xs} -> x ∈ xs -> x ∈ y ∷ xs
The type signature is equivalent to
data _∈_ {α} {A : Set α} : A -> List A -> Set where
_∈_ is a relation between elements of type A and lists of elements of type A.
The universe monomorphic variant of REL is itself a binary relation:
MonoREL : REL Set Set (Level.suc Level.zero)
MonoREL A B = A → B → Set
To define a binary relation we need two sets, so REL needs, at least, two types. The type of REL:
REL : ∀ {a b} → Set a → Set b → (ℓ : Level) → Set (a ⊔ b ⊔ suc ℓ)
This type is a bit polluted due to universe level stuff. If you allow yourself a bit of informality, you can disable universe levels (more information about this here) and write REL as:
REL : Set -> Set -> Set
which is a type that expects two types as parameters.
The use of universes in type theory is to avoid paradoxes like Russell's Paradox of set theory.
I'm not a type theory expert, but the interpretation of REL type can be summarised as:
Set a and Set b are parameters types of universe levels a andb, respectively.
The operator ⊔ returns the maximum of two parameter levels.
Hope that this can help you.
Related
During some development using cubical-agda, I noticed (and later checked) that my current goal, if proven would also imply such theorem:
parametric? : ∀ ℓ → Type (ℓ-suc ℓ)
parametric? ℓ = (f : {A : Type ℓ} → List A ≃ List A)
→ (A : Type ℓ) → length ∘ equivFun (f {A}) ≡ length
I suspect that this is example of parametric theorem, which is true, but is unprovable in cubical agda. Is it the case?
Can I safely assume that my current goal is also unprovable?
Yes, because it's false in the standard (simplicial sets) model.
If excluded middle holds, we can define f : {A : Type ℓ} → List A ≃ List A by first doing a case analysis on whether A is contractible or not. If A is not contractible, f gives the identity equivalence, but if A is contractible, then List A is equivalent to Nat, and, f can give an equivalence that, e.g., permutes odds and evens.
Suppose I have a record type for some algebraic structure; e.g. for monoids:
{-# OPTIONS --cubical #-}
module _ where
open import Cubical.Core.Everything
open import Cubical.Foundations.Everything hiding (assoc)
record Monoid {ℓ} (A : Type ℓ) : Type ℓ where
field
set : isSet A
_⋄_ : A → A → A
e : A
eˡ : ∀ x → e ⋄ x ≡ x
eʳ : ∀ x → x ⋄ e ≡ x
assoc : ∀ x y z → (x ⋄ y) ⋄ z ≡ x ⋄ (y ⋄ z)
Then I can manually create a type for monoid homomorphisms:
record Hom {ℓ ℓ′} {A : Type ℓ} {B : Type ℓ′} (M : Monoid A) (N : Monoid B) : Type (ℓ-max ℓ ℓ′) where
open Monoid M renaming (_⋄_ to _⊕_)
open Monoid N renaming (_⋄_ to _⊗_; e to ε)
field
map : A → B
map-unit : map e ≡ ε
map-op : ∀ x y → map (x ⊕ y) ≡ map x ⊗ map y
But is there a way to define Hom without spelling out the homomorphism laws? So as some kind of mapping from the witness M : Monoid A to N : Monoid B, but that doesn't make much sense to me because it'd be a "mapping" where we already know that it should map M to N...
There currently isn't. But that's what the follow up to the recent paper A feature to unbundle data at will is about. In the repo for that work, you'll find the sources for 'package former'; the accompanying documentation uses Monoid as one of its examples, and section 2.17 is all about homomorphism generation.
The aim of this prototype is to figure out what features are needed (and feasible), to guide the development of both the meta-theory and an 'inside Agda' implementation.
Background: I have some basic understanding of Agda and I'm trying to understand
the gist here:
https://gist.github.com/copumpkin/5945905
But I'm having problems understanding all the Pred stuff and the use of
universes.
This is the definition of Pred:
Pred : ∀ {a} → Set a → (ℓ : Level) → Set (a ⊔ suc ℓ)
Pred A ℓ = A → Set ℓ
-- Unary relations can be seen as sets
Why would I ever want such a type and what does that comment mean? It's being
used everywhere so I can't really proceed without understanding.
Following that, there's the record definition for a topological space:
record Space x ℓ : Set (Level.suc x ⊔ Level.suc ℓ) where
What is this magic? I kind of understand that x is the level of our "points",
but what is ℓ and the resultant type?
There was a related question about binary relations.
Under the Curry–Howard interpretation each A of type Set (or Set ℓ in a universe polymorphic setting) is a proposition. Thus P of type A -> Set for some A is a predicate defined on elements of A.
Consider e.g. a predicate Positive which holds only for natural numbers of the form suc n for some n (I'm out of my machine hence the ASCII):
data Positive : Nat -> Set where
positive : forall n -> Positive (suc n)
positive n is a (or, rather, the) proof of Positive (suc n). Having Pred A = A -> Set we can write the type signature of Positive as
data Positive : Pred Nat where
Another example is All from the Data.List.All module in the standard library. It's defined as
data All {a p} {A : Set a}
(P : A → Set p) : List A → Set (p ⊔ a) where
[] : All P []
_∷_ : ∀ {x xs} (px : P x) (pxs : All P xs) → All P (x ∷ xs)
All P is a predicate that holds for any list xs whenever P holds for each element of the list. Using the universe polymorphic definition of Pred we can write the type signature of All as
data All {a p} {A : Set a}
(P : Pred A p) : Pred (List A) (p ⊔ a) where
(and make it clear that All is a predicate transformer). So Pred is mostly notational convenience.
As to universe polymorphism there are some docs in the old Agda wiki. In your example x is the level of the universe where the type of points (X) lies. That ℓ is used in Pred (Pred X ℓ) ℓ — the type of predicates defined on predicates defined on elements of X (I can't comment on the topological meaning of this expression). Set x lies in Set (suc x) and Pred (Pred X ℓ) ℓ (which unfolds into (X -> Set ℓ) -> Set ℓ) lies in Set (suc ℓ) hence the whole Space x ℓ lies in Set (suc x ⊔ suc ℓ).
In the following data type,
data _≡_ {A : Set} (x : A) : A → Set where
refl : x ≡ x
I am trying to understand this like:
If A is of type Set and is implicit and x is the first argument and of type A, then this will construct a data of type A → Set.
Please explain it. I did not get from where it getting second x, in constructor refl.
The crucial distinction here is between parameters (A and x in this case) and indices (the A in A → Set).
The parameters are located on the left hand side of the colon in the data declaration. They are in scope in the body of the type and may not vary (hence their name). This is what allows you to write data declarations such as List where the type of the elements contained in the List is stated once and for all:
data List (A : Set) : Set where
nil : List A
cons : A → List A → List A
rather than having to mention it in every single constructor with a ∀ A →:
data List : Set → Set1 where
nil : ∀ A → List A
cons : ∀ A → A → List A → List A
The indices are located on the right hand side of the colon in the data declaration. They can be either fresh variables introduced by a constructor or constrained to be equal to other terms.
If you work with natural numbers you can, for instance, build a predicate stating that a number is not zero like so:
open import Data.Nat
data NotZero : (n : ℕ) → Set where
indeed1 : NotZero (suc zero)
indeed2+ : ∀ p → NotZero (suc (suc p))
Here the n mentioned in the type signature of the data declaration is an index. It is constrained differently by different constructors: indeed1 says that n is 1 whilst indeed2+ says that n has the shape suc (suc p).
Coming back to the declaration you quote in your question, we can reformulate it in a fully-explicit equivalent form:
data Eq (A : Set) (x : A) : (y : A) → Set where
refl : Eq A x x
Here we see that Eq has two parameters (A is a set and x is an element of A) and an index y which is the thing we are going to claim to be equal to x. refl states that the only way to build a proof that two things x and y are equal is if they are exactly the same; it constraints y to be exactly x.
I'm working in a simple library containing definitions and properties about substitutions for simple types. I'm using the following encoding for types:
data Ty (n : Nat) : Set where
var : Fin n -> Ty n
con : Ty n
app : Ty n -> Ty n -> Ty n
so, since variables are represented as finite sets, substitutions are just vectors:
Subst : Nat -> Nat -> Set
Subst n m = Vec (Ty m) n
The complete development is in the following paste: http://lpaste.net/107751
Using this encoding, I have defined several lemmas about such substitutions, but I do not know how to define a theorem that specifies that substitutions are idempotent. I believe that I must use some property like weakening in order to express this, but I can't figure out how.
Could someone give any directions or clues?
Thanks in advance.
Substitutions that produce expressions over fresh variables are indeed idempotent. But in order to express this theorem, you have to consider your substitution Subst n m as one operating on the joint variable set Subst (n + m) (n + m). Here is a variant that uses arbitrary variable sets A and B instead of Fin n and Fin m.
open import Relation.Binary.PropositionalEquality using (_≡_; refl)
-- Disjoint union.
data _+_ (A B : Set) : Set where
left : A → A + B
right : B → A + B
-- A set of variable names can be any type.
Names = Set
-- Simple expressions over a set of names.
data Tm (A : Names) : Set where
var : A → Tm A
app : Tm A → Tm A → Tm A
-- Substitute all variables from set A by terms over a name set B.
Subst : Names → Names → Set
Subst A B = A → Tm B
subst : ∀{A B} → Subst A B → Tm A → Tm B
subst σ (var x) = σ x
subst σ (app t u) = app (subst σ t) (subst σ u)
-- Rename all variables from set A to names from set B.
Rename : Names → Names → Set
Rename A B = A → B
rename : ∀{A B} → Rename A B → Tm A → Tm B
rename σ (var x) = var (σ x)
rename σ (app t u) = app (rename σ t) (rename σ u)
-- In order to speak about idempotency of substitutions whose domain A
-- is disjoint from the variable set B used in the range, we have to promote
-- them to work on the union A+B of variable sets.
-- The promoted substitution is the identity on B,
-- and the original substitution on A, but with the result transferred from B to A + B.
promote : ∀{A B} → Subst A B → Subst (A + B) (A + B)
promote σ (left x) = rename right (σ x)
promote σ (right x) = var (right x)
module _ {A B : Set} (σ₀ : Subst A B) where
-- Now assume a promoted substitution.
σ = promote σ₀
-- A promoted substitution has no effect on terms with variables only in B.
lemma : ∀ t → subst σ (rename right t) ≡ rename right t
lemma (var x) = refl
lemma (app t u) rewrite lemma t | lemma u = refl
-- Hence, it is idempotent.
idempotency : ∀ x → subst σ (σ x) ≡ σ x
idempotency (right x) = refl
idempotency (left x) = lemma (σ₀ x)