Stuck on unification problems during case splitting - agda

Suppose we have the following code:
open import Data.Fin
open import Data.Nat
data SType : ℕ → Set where
variable
ℓ : ℕ
ι : Fin ℓ
τ τ' : SType ℓ
infixl 5 _,_
data Ctx : ℕ → Set where
⊘ : Ctx zero
_,_ : Ctx ℓ → SType ℓ → Ctx (suc ℓ)
variable Γ : Ctx ℓ
postulate weaken : SType ℓ → SType (suc ℓ)
infix 4 _∈_at_
data _∈_at_ : SType ℓ → Ctx ℓ → Fin ℓ → Set where
∈-zero : weaken τ ∈ Γ , τ at zero
∈-suc : τ ∈ Γ at ι
→ weaken τ ∈ Γ , τ' at suc ι
which models a tiny part of a well-scoped representation of a type system (and I'm keeping weaken postulated and SType not having any constructors for the sake of brevity).
Now suppose we want to write a function that's basically an "inverse" of the ∈-suc constructor:
∈-chop : weaken τ ∈ Γ , τ' at suc ι
→ τ ∈ Γ at ι
∈-chop ∈ = {! !}
Now, if we try to split on ∈, Agda will get all doubting and hesitant:
I'm not sure if there should be a case for the constructor ∈-suc,
because I get stuck when trying to solve the following unification
problems (inferred index ≟ expected index):
{suc τ.ℓ₁} ≟ {suc τ.ℓ₂}
weaken τ₁ ≟ weaken τ₂
Γ₁ , τ'' ≟ Γ₂ , τ'''
suc ι₁ ≟ suc ι₂
when checking that the expression ? has type τ ∈ Γ at ι
Why is it not sure, and what's the best way to fix this?

Your problem is the Green Slime.
Quoting Jesper Cockx:
The error message "cannot generalize over the indices" is thrown by Agda when it encounters a unification problem of the form c us =?= c vs where c is a constructor of an indexed datatype, but the indices in the type of this equation are something other than distinct variables (i.e. they
should be fully general). If they are not, Agda tries to apply a technique called higher-dimensional unification (see our CPP 2017 paper) to bring them in a fully general form. However, this unfortunately doesn't always succeed, for example in your code it gets stuck on the + function in the index of con.
One way to fix your problem would be to get rid of the 'green slime' in the type of con: it's better to use only variables and constructors in the indices of your datatypes, and use explicit proofs of equality for the heavier work.
You can check that this is indeed the case by making weaken a constructor of SType, which then allows you to define ∈-chop by pattern matching like you want.
Matching on ∈-suc amounts to solving
weaken τ ∈ Γ , τ' at suc ι =?= weaken _τ ∈ _Γ , _τ' at suc _ι
where the LHS is the type that you provided in the type signature and the RHS is the inferred type of ∈-suc where each implicit variable got turned into a meta. Now unifying, say, suc ι and suc _ι is no problem, since constructors are injective, but functions are generally not (see the first part of this answer) and so when weaken is a function you can't unify weaken τ with weaken _τ.
You can use explicit equality to get around the issue:
open import Relation.Binary.PropositionalEquality
infix 4 _∈_at_
data _∈_at_ : SType ℓ → Ctx ℓ → Fin ℓ → Set where
∈-zero : τ' ≡ weaken τ → τ' ∈ Γ , τ at zero
∈-suc : τ' ≡ weaken τ
→ τ ∈ Γ at ι
→ τ' ∈ Γ , τ at suc ι
That allows you to pattern match in ∈-chop even when weaken is a function.

Your definitions seem to imply that, in ∈-chop there are no possible value for τ which can be seen as follows:
∈-chop : ∀ {Γ τ ι} → weaken τ ∈ Γ , τ' at suc ι → τ ∈ Γ at ι
∈-chop {τ = ()}
This does not directly answer your question but it's probably not the indented behavior which could ultimately solve your problem.

Related

Intuition for difference between eta for function from top and empty functions in Agda

In Agda, it seems it is not possible to show ∀ {A : Set} (f : ⊥ → A) → f ≡ λ ().
However, the seemingly similar term ∀ {A : Set} (f : ⊤ → A) → f ≡ λ _ → f tt can be proven by refl. It can be later used to prove a form of extensionality for ⊤:
ext⊤ : ∀ {A : Set} (f g : ⊤ → A) (H : ∀ x → f x ≡ g x) → f ≡ g
According to this question and answer, the explanation might be in considering different models of type theory. Is it possible to have any intuition on why one is accepted and not the other? Shouldn't f ≡ λ () be some form of eta law?
The ⊤ type has the eta rule which says that any terms with that type are definitionally equal. Hence, f ≡ (λ x → f x) ≡ (λ x → f tt).
⊥ does not have an eta rule in Agda. If f : ⊥ → A, then we only know that f ≡ λ x → f x. λ () is essentially syntactic sugar for ⊥-elim, and f is not definitionally equal to ⊥-elim.
I draw your attention that the first statement is attempting to prove the uniqueness of ⊥ → A. Usually it is true up to isomorphism.
The full correspondence would have been between ∀ {A : Set} (f : ⊤ → A) → f ≡ λ _ → f tt and ∀ {A : Set} (f : ⊥ → A) → f ≡ λ _ → f () - the expression for ⊤ constructs the value tt, so you should be constructing a value for ⊥.
Agda has no means of constructing a value of ⊥, so () is not a valid constructor, it is only a placeholder for what you want.
Although it isn't really pattern-matching, it probably is not harmful to see the use of () as pattern-matching for the empty type - it is allowed to occur only in the pattern-matching positions.
This is intended to show the similarity is superficial, so should amend your intuition about the expressions.
Shouldn't f ≡ λ () be some form of eta law?
It is not clear what you would gain from that. Many things can be proven only up to isomorphism. So, for example, proving the uniqueness of ⊥ → A could correspond to proving the uniqueness of A → ⊤ (not eta-equality of f and λ _ → f tt). Both of these is doable.

Can I use inductive type families in Cubical Agda?

I noticed that the Cubical standard library defines Fin as a dependent pair instead of an indexed inductive type. The reason why is that Cubical Agda does not fully support indexed inductive types: https://github.com/agda/cubical/pull/104#discussion_r268476220
A linked issue states that pattern matching doesn't work on inductive families because hcomp and transp haven't been defined on them: https://github.com/agda/cubical/pull/57#issuecomment-461174095
I defined Fin and Vec and wrote a pattern-matching function, and it seems to work fine:
{-# OPTIONS --cubical --safe #-}
open import Cubical.Foundations.Prelude
open import Cubical.Data.Nat using (ℕ; zero; suc)
private
variable
ℓ : Level
A : Type ℓ
n : ℕ
data Fin : ℕ → Type₀ where
fzero : Fin (suc n)
fsuc : Fin n → Fin (suc n)
data Vec (A : Type ℓ) : ℕ → Type ℓ where
[] : Vec A zero
_∷_ : A → Vec A n → Vec A (suc n)
_[_] : Vec A n → Fin n → A
(x ∷ _) [ fzero ] = x
(_ ∷ xs) [ fsuc n ] = xs [ n ]
p : (1 ∷ (2 ∷ [])) [ fzero ] ≡ 1
p = refl
Yet this issue is still open: https://github.com/agda/agda/issues/3733
I want to use Cubical Agda just in case I need higher inductive types or function extensionality, but I don't want to give up Vec or the indexed definition of Fin. I am unfamiliar with the details of Cubical Type Theory, so I don't know where hcomp and transp would be invoked. What is the current status of inductive families in Cubical Agda? Can I still use them if I avoid certain operations?
It is fine to use inductive families with cubical agda, and pattern matching definitions work in the sense that they do compute for the declared constructors of the family.
The limitation that will be addressed by https://github.com/agda/agda/issues/3733 is the following:
A term like subst Fin refl fzero will not compute to fzero or any other constructor, which also means that
(x ∷ _) [ subst Fin refl fzero ]
will not compute to x either.
We can still prove subst Fin refl fzero ≡ fzero by substRefl from the library, so we can also prove (x ∷ _) [ subst Fin refl fzero ] ≡ x.
So currently it is a choice between using inductive families and dealing with subst and transport getting stuck on them, or otherwise encoding everything with paths and lose the nice pattern matching.

Representing homomorphisms without writing all laws out

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.

Undersand Unary Relations and Universe polymorphism

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 ℓ).

Non trivial negation in agda

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)
?

Resources