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 ℓ).
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.
I'm playing around with the type of finite multisets as defined in the cubical standard library here:
https://github.com/agda/cubical/blob/0d272ccbf6f3b142d1b723cead28209444bc896f/Cubical/HITs/FiniteMultiset/Base.agda#L15
data FMSet (A : Type ℓ) : Type ℓ where
[] : FMSet A
_∷_ : (x : A) → (xs : FMSet A) → FMSet A
comm : ∀ x y xs → x ∷ y ∷ xs ≡ y ∷ x ∷ xs
trunc : isSet (FMSet A)
I was able to reproduce the proofs for count extensionality and one of my lemmas I showed that you can remove a element from both sides of an equality and keep the equality.
It was similar to this one: https://github.com/agda/cubical/blob/0d272ccbf6f3b142d1b723cead28209444bc896f/Cubical/HITs/FiniteMultiset/Properties.agda#L183
remove1-≡-lemma : ∀ {a} {x} xs → a ≡ x → xs ≡ remove1 a (x ∷ xs)
remove1-≡-lemma {a} {x} xs a≡x with discA a x
... | yes _ = refl
... | no a≢x = ⊥.rec (a≢x a≡x)
My proofs weren't using the same syntax but in the core libraries syntax it was
cons-path-lemma : ∀ {x} xs ys → (x ∷ xs) ≡ (x ∷ ys) → xs ≡ ys
where the proof is using remove1-≡-lemma path composed on both side of a path which is the argument path functionally composed with remove1 x.
This requires the type of the values to have decidable equality as remove1 doesn't make sense without it. But the lemma itself doesn't mention decidable equality, and so I thought I would try to prove it without having that as a hypothesis. Its now a week later and I'm at my wits end because this seems so 'obvious' but so stubborn to prove.
I'm thinking that my intuition about this being provable may be coming from my classical math background, and so it doesn't follow constructively/contiuously.
So my question is: Is this provable with no assumptions on the element type? If so what would the general structure of the proof look like, I have had trouble getting proofs that want to induct over the two FMSets simultaneously to work (as I'm mostly guessing when trying to get paths to line up as necessary). If it is not provable with no assumptions, is it possible to show that it is equivalent in some form to the necessary assumptions?
I can't offer a proof but an argument why it should be provable without assuming decidability. I think finite multisets can be represented as functions Fin n -> A and equality between multisets f and g is given by a permutation phi : Fin n ~ Fin n, (that is invertible functions on Fin n) such that f o phi = g. Now
(a :: f) 0 = a
(a :: f) (suc i) = f i
If phi : Fin (suc n) ~ Fin (suc n) proves that a :: f = a :: g you can construct a psi : Fin n ~ Fin n which proves that f = g. If phi 0 = 0 then psi n = phi (suc n) otherwise you have to obtain psi by assigning phi^-1 0 to phi 0. However this case analysis is on Fin n.
I think representing the permutation group by swapping adjacent elements is just an inconvenient representation for this problem.
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.
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.
All negations, i.e. conclusions of the form A -> Bottom in agda that I've seen came from absurd pattern matchings. Are there any other cases where it's possible to get negation in agda? Are there any other cases in dependent type theory where it's possible?
Type theories usually don't have a notion of pattern matching (and by extension absurd patterns) and yet they can prove negation of the sort you are describing.
First of all, we'll have to look at data types. Without pattern matching, you characterise them by introduction and elimination rules. Introduction rules are basically constructors, they tell you how to construct a value of that type. On the other hand, elimination rules tell you how to use a value of that type. There are also associated computation rules (β-reduction and sometimes η-reduction), but we needn't deal with those now.
Elimination rules look a bit like folds (at least for positive types). For example, here's how an elimination rule for natural numbers would look like in Agda:
ℕ-elim : ∀ {p} (P : ℕ → Set p)
(s : ∀ {n} → P n → P (suc n))
(z : P 0) →
∀ n → P n
ℕ-elim P s z zero = z
ℕ-elim P s z (suc n) = s (ℕ-elim P s z n)
While Agda does have introduction rules (constructors), it doesn't have elimination rules. Instead, it has pattern matching and as you can see above, we can recover the elimination rule with it. However, we can also do the converse: we can simulate pattern matching using elimination rules. Truth be told, it's usually much more inconvenient, but it can be done - the elimination rule mentioned above basically does pattern matching on the outermost constructor and if we need to go deeper, we can just apply the elimination rule again.
So, we can sort of simulate pattern matching. What about absurd patterns? As an example, we'll take fourth Peano axiom:
peano : ∀ n → suc n ≡ zero → ⊥
However, there's a trick involved (and in fact, it's quite crucial; in Martin-Löf's type theory without universes you cannot do it without the trick, see this paper). We need to construct a function that will return two different types based on its arguments:
Nope : (m n : ℕ) → Set
Nope (suc _) zero = ⊥
Nope _ _ = ⊤
If m ≡ n, we should be able to prove that Nope m n holds (is inhabitated). And indeed, this is quite easy:
nope : ∀ m n → m ≡ n → Nope m n
nope zero ._ refl = _
nope (suc m) ._ refl = _
You can now sort of see where this is heading. If we apply nope to the "bad" proof that suc n ≡ zero, Nope (suc n) zero will reduce to ⊥ and we'll get the desired function:
peano : ∀ n → suc n ≡ zero → ⊥
peano _ p = nope _ _ p
Now, you might notice that I cheated a bit. I used pattern matching even though I said earlier that these type theories don't come with pattern matching. I'll remedy that for the next example, but I suggest you try to prove peano without pattern matching on the numbers (use ℕ-elim given above); if you really want a hardcore version, do it without pattern matching on equality as well and use this eliminator instead:
J : ∀ {a p} {A : Set a} (P : ∀ (x : A) y → x ≡ y → Set p)
(f : ∀ x → P x x refl) → ∀ x y → (p : x ≡ y) → P x y p
J P f x .x refl = f x
Another popular absurd pattern is on something of type Fin 0 (and from this example, you'll get the idea how other such absurd matches could be simulated). So, first of all, we'll need eliminator for Fin.
Fin-elim : ∀ {p} (P : ∀ n → Fin n → Set p)
(s : ∀ {n} {fn : Fin n} → P n fn → P (suc n) (fsuc fn))
(z : ∀ {n} → P (suc n) fzero) →
∀ {n} (fn : Fin n) → P n fn
Fin-elim P s z fzero = z
Fin-elim P s z (fsuc x) = s (Fin-elim P s z x)
Yes, the type is really ugly. Anyways, we're going to use the same trick, but this time, we only need to depend on one number:
Nope : ℕ → Set
Nope = ℕ-elim (λ _ → Set) (λ _ → ⊤) ⊥
Note that is equivalent to:
Nope zero = ⊥
Nope (suc _) = ⊤
Now, notice that both cases for the eliminator above (that is, s and z case) return something of type P (suc n) _. If we choose P = λ n _ → Nope n, we'll have to return something of type ⊤ for both cases - but that's easy! And indeed, it was easy:
bad : Fin 0 → ⊥
bad = Fin-elim (λ n _ → Nope n) (λ _ → _) _
The last thing you might be wondering about is how do we get value of any type from ⊥ (known as ex falso quodlibet in logic). In Agda, we obviously have:
⊥-elim : ∀ {w} {Whatever : Set w} → ⊥ → Whatever
⊥-elim ()
But it turns out that this is precisely the eliminator for ⊥, so it is given when defining this type in type theory.
Are you asking for something like
open import Relation.Nullary
→-transposition : {P Q : Set} → (P → Q) → ¬ Q → ¬ P
→-transposition p→q ¬q p = ¬q (p→q p)
?