How to convert the J axiom to the fixed-argument form? - agda

I was trying to prove that true ≡ false -> Empty assuming the J axiom. It is defined as:
J : Type
J = forall
{A : Set}
{C : (x y : A) → (x ≡ y) → Set} →
(c : ∀ x → C x x refl) →
(x y : A) →
(p : x ≡ y) →
C x y p
My attempt went like this:
bad : J → true ≡ false -> Empty
bad j e = j Bool (λ { true _ _ => Unit; false _ _ => Empty }) _
Now, to proceed with the proof, I needed a term c : ∀ x -> C x x refl. Since I instantiated C, it becomes c : ∀ x -> (λ { true _ _ => Unit; false _ _ => Empty } x x refl. Then I got stuck. c can't reduce further because we don't know the value of x. I wasn't able to complete this proof. But there is a different version of J:
J' : Type
J' = forall
{A : Set}
{x : A}
{C : (y : A) → (x ≡ y) → Set} →
(c : C x refl) →
(y : A) →
(p : x ≡ y) →
C y p
With this one, this problem is solved, because t can be fixed to be true. This makes the c argument reduce to Unit, which we can provide. My question is: can we convert the former version to the later? That is, can we build a term fix_x : J → J'? Does that hold in general (i.e., can indices be converted to parameters)?

First, regarding true ≡ false -> Empty: this is unprovable if you can only eliminate into Set0 with J, so you need an universe polymorphic or large definition. I write some preliminaries here:
{-# OPTIONS --without-K #-}
open import Relation.Binary.PropositionalEquality
open import Level
data Bool : Set where true false : Bool
data Empty : Set where
record Unit : Set where
constructor tt
JTy : ∀ {i j} → Set _
JTy {i}{j} =
{A : Set i}
(P : (x y : A) → (x ≡ y) → Set j) →
(pr : ∀ x → P x x refl) →
{x y : A} →
(p : x ≡ y) →
P x y p
J : ∀ {i}{j} → JTy {i}{j}
J P pr {x} refl = pr x
J₀ = J {zero}{zero}
Now, transport or subst is the only needed thing for true ≡ false -> Empty:
transp : ∀ {i j}{A : Set i}(P : A → Set j){x y} → x ≡ y → P x → P y
transp P = J (λ x y _ → P x -> P y) (λ _ px → px)
true≢false : true ≡ false → Empty
true≢false e = transp (λ {true → Unit; false → Empty}) e tt
Considering now proving the pointed J' from J, I know about three solutions, and each uses different features from the ambient theory.
The simplest one is to use universes to abstract over the induction motive:
JTy' : ∀ {i j} → Set _
JTy' {i}{j} =
{A : Set i}
{x : A}
(P : ∀ y → x ≡ y → Set j)
(pr : P x refl)
{y : A}
(p : x ≡ y)
→ P y p
JTy→JTy' : (∀ {i j} → JTy {i}{j}) → ∀ {i}{j} → JTy' {i}{j}
JTy→JTy' J {i} {j} {A} {x} P pr {y} e =
J (λ x y e → (P : ∀ y → x ≡ y → Set j) → P x refl → P y e)
(λ x P pr → pr) e P pr
If we only want to use a fixed universe level, then it is a bit more complicated. The following solution, sometimes called "contractible singletons", needs Σ-types, but nothing else:
open import Data.Product
JTy→JTy'withΣ : JTy {zero}{zero} → JTy' {zero}{zero}
JTy→JTy'withΣ J {A} {x} P pr {y} e =
J (λ {(x , r) (y , e) _ → P x r → P y e})
(λ _ px → px)
(J (λ x y e → (x , refl) ≡ (y , e))
(λ _ → refl)
e)
pr
There is a solution which doesn't even need Σ-s, but requires the beta rule for J, which says that J P pr {x} refl = pr x. It doesn't matter whether this rule holds definitionally or just as a propositional equality, but the construction is simpler when it holds definitionally, so let's do that. Note that I don't use any universe other than Set0.
transp₀ = transp {zero}{zero}
transp2 : ∀ {A : Set}{B : A → Set}(C : ∀ a → B a → Set)
{x y : A}(e : x ≡ y){b} → C x b → C y (transp₀ B e b)
transp2 {A}{B} C {x}{y} e {b} cxb =
J₀ (λ x y e → ∀ b → C x b → C y (transp₀ B e b)) (λ _ _ cxb → cxb) e b cxb
JTy→JTy'noΣU : JTy' {zero}{zero}
JTy→JTy'noΣU {A} {x} P pr {y} e =
transp₀ (P y) (J₀ (λ x y e → transp₀ (x ≡_) e refl ≡ e) (λ _ → refl) e)
(transp2 {A} {λ y → x ≡ y} P e pr)
Philosophically, the third version is the most "conservative", since it only assumes J. The addition of the beta rule is not really an extra thing, since it is always assumed to hold (definitionally or propositionally) for _≡_.
can indices be converted to parameters?
If you have propositional equality, then all indices can be converted to parameters, and fixed in constructors using equality proofs.

Related

How is Agda inferring the implicit argument to `Vec.foldl`?

foldl : ∀ {a b} {A : Set a} (B : ℕ → Set b) {m} →
(∀ {n} → B n → A → B (suc n)) →
B zero →
Vec A m → B m
foldl b _⊕_ n [] = n
foldl b _⊕_ n (x ∷ xs) = foldl (λ n → b (suc n)) _⊕_ (n ⊕ x) xs
When translating the above function to Lean, I was shocked to find out that its true form is actually like...
def foldl : ∀ (P : ℕ → Type a) {n : nat}
(f : ∀ {n}, P n → α → P (n+1)) (s : P 0)
(l : Vec α n), P n
| P 0 f s (nil _) := s
| P (n+1) f s (cons x xs) := foldl (fun n, P (n+1)) (λ n, #f (n+1)) (#f 0 s x) xs
I find it really impressive that Agda is able to infer the implicit argument to f correctly. How is it doing that?
foldl : ∀ {a b} {A : Set a} (B : ℕ → Set b) {m} →
(∀ {n} → B n → A → B (suc n)) →
B zero →
Vec A m → B m
foldl b _⊕_ n [] = n
foldl b _⊕_ n (x ∷ xs) = foldl (λ n → b (suc n)) _⊕_ (_⊕_ {0} n x) xs
If I pass it 0 explicitly as in the Lean version, I get a hint as to the answer. What is going on is that Agda is doing the same thing as in the Lean version, namely wrapping the implicit arg so it is suc'd.
This is surprising as I thought that implicit arguments just means that Agda should provide them on its own. I did not think it would change the function when it is passed as an argument.

Why do function composition and application have a dependent implementation in Agda?

Why do function composition (∘) and application ($) have the implementation as available in https://github.com/agda/agda-stdlib/blob/master/src/Function.agda#L74-L76?
Copied here for convenience:
_∘_ : ∀ {a b c}
{A : Set a} {B : A → Set b} {C : {x : A} → B x → Set c} →
(∀ {x} (y : B x) → C y) → (g : (x : A) → B x) →
((x : A) → C (g x))
f ∘ g = λ x → f (g x)
_∘'_ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c} →
(B → C) → (A → B) → (A → C)
f ∘' g = λ x → f (g x)
_$_ : ∀ {a b} {A : Set a} {B : A → Set b} →
((x : A) → B x) → ((x : A) → B x)
f $ x = f x
_$'_ : ∀ {a b} {A : Set a} {B : Set b} →
(A → B) → (A → B)
f $' x = f x
I initially thought the rationale behind this was that $ would be able to handle higher order types that $' wouldn't be able to handle. For example, consider A=Nat, B=List, f is ::, where B depends on A. But after a lot of testing, I couldn't come up with an example that would show that the implementation of $' is not sufficient. What scenarios does $ handle that $' isn't able to handle? (Similarly, what scenarios does ∘ handle that ∘' doesn't?
open import Agda.Builtin.Nat public
open import Agda.Primitive public
--data List {a} (A : Set a) : Set a where
-- [] : List A
-- _∷_ : (x : A) (xs : List A) → List A
data Vec {a} (A : Set a) : Nat → Set a where
[] : Vec A zero
_∷_ : ∀ {n} (x : A) (xs : Vec A n) → Vec A (suc n)
tail : ∀ {a n} {A : Set a} → Vec A (suc n) → Vec A n
tail (x ∷ s) = s
_$_ : ∀ {a b} {A : Set a} {B : A → Set b} →
((x : A) → B x) → ((x : A) → B x)
f $ x = f x
_$'_ : ∀ {a b} {A : Set a} {B : Set b} →
(A → B) → (A → B)
f $' x = f x
_∘_ : ∀ {a b c}
{A : Set a} {B : A → Set b} {C : {x : A} → B x → Set c} →
(∀ {x} (y : B x) → C y) → (g : (x : A) → B x) →
((x : A) → C (g x))
f ∘ g = λ x → f (g x)
_∘'_ : ∀ {a b c} {A : Set a} {B : Set b} {C : Set c} →
(B → C) → (A → B) → (A → C)
f ∘' g = λ x → f (g x)
Vecc : ∀ {a} → Nat → (A : Set a) → (Set a)
Vecc x y = Vec y x
data Pair {a b} (A : Set a) (B : A → Set b) : Set (a ⊔ b) where
_,_ : (x : A) → (y : B x) → Pair A B
-- Dependent Pair attempt
--fst : ∀ {a b} {A : Set a} {B : A → Set b} → Pair A B → A
--fst (a , b) = a
--
--f : Pair Nat $' Vec Nat
--f = _,_ zero $' []
--
--g : Pair (Pair Nat $' Vec Nat) $' λ x → Nat
--g = _,_ (_,_ zero $' []) $' zero
-- Some other attempt
--f : ∀ {a n} {A : Set a} → Vec A ((suc ∘' suc) n) → Vec A n
--f {a} = tail {a} ∘' tail {a}
-- Vec attempt
--f : ∀ {a} (A : Set a) → (Set a)
--f {a} = Vecc {a} (suc zero) ∘' Vecc {a} (suc zero)
--
--h = f Nat
--
--x : h
--x = (zero ∷ []) ∷ []
-- List attempt
--f : ∀ {a} (A : Set a) → (Set a)
--f {a} = List {a} ∘' List {a}
--
--g : ∀ {a} (A : Set a) → (Set a)
--g {a} = List {a} ∘ List {a}
--
--h = f Nat
--i = g Nat
--
--x : h
--x = (zero ∷ []) ∷ []
∘′ and $′ don't work with dependent functions. You simply didn't try any tests with dependent functions. For f $ x examples, f must be dependent, for f ∘ g, either of the functions must be dependent. Example:
open import Data.Nat
open import Data.Vec
open import Function
open import Relation.Binary.PropositionalEquality
replicate' : {A : Set} → A → (n : ℕ) → Vec A n
replicate' a n = replicate a
refl' : {A : Set}(a : A) → a ≡ a
refl' a = refl
-- fail1 : Vec ℕ 10
-- fail1 = replicate' 10 $′ 10
ok1 : Vec ℕ 10
ok1 = replicate' 10 $ 10
-- fail2 : ∀ n → replicate' 10 n ≡ replicate' 10 n
-- fail2 = refl' ∘′ replicate' 10
ok2 : ∀ n → replicate' 10 n ≡ replicate' 10 n
ok2 = refl' ∘ replicate' 10
One works with dependent functions, the other doesn't, as Andras Kovacs mentioned.
The important difference is that for non-dependent functions stronger proofs can be constructed. For example:
eq : {A B} -> f : (A -> B) -> x y : A -> x == y -> (f x) == (f y)
eq f x .x refl = refl
Here we can construct equality of f x and f y. But we can't do the same for dependent functions - because there is no way to prove B x == B y. So there is only a weaker proof that f x can be "cast" to f y.
transport : {A} {B : A -> Set} -> f : (x : A -> B x) -> x y : A -> x == y -> f x -> f y
transport f x .x refl fx = fx
(Actually, transport is usually defined as B x -> B y, not for a dependent function; but I just can't come up with a better name)

Implementation of Transitivity of Equality in Agda (HoTT)

After hours of trying different versions of it, I give up. I just want to typecheck a proof of the transitivity of equality as stated in the HoTT-Book. I'm new to Agda so it might be just a small flaw or perhaps a bigger one... dont know. I consulted different libs for HoTT in Agda, but the ones I found had (in my eyes) rather complex solutions.
trans : ∀ {ℓ} (A : Type ℓ) (x y : A)
→ (x == y) → (z : A) → (y == z) → (x == z)
trans A x y = pathInd (λ p → (z : A) → (y == z) → (x == z))
(λ x → pathInd (λ x → (z : A) → (x == z) → (x == z))) (λ x → refl x))
Its based on the following implementation of path induction.
pathInd : ∀ {m n} {A : Type m} (P : {x y : A} → (x == y) → Type n) →
(∀ x → P (refl x)) → ∀ {x y} (p : (x == y)) → P p
pathInd P r (refl x) = r _
Thanks for any help.

Agda type-safe cast / coercion

I found handy a function:
coerce : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
coerce refl x = x
when defining functions with indexed types. In situations where indexes are not definitionally equal i,e, one have to use lemma, to show the types match.
zipVec : ∀ {a b n m } {A : Set a} {B : Set b} → Vec A n → Vec B m → Vec (A × B) (n ⊓ m)
zipVec [] _ = []
zipVec {n = n} _ [] = coerce (cong (Vec _) (0≡n⊓0 n)) []
zipVec (x ∷ xs) (y ∷ ys) = (x , y) ∷ zipVec xs ys
Note, yet this example is easy to rewrite so one don't need to coerce:
zipVec : ∀ {a b n m } {A : Set a} {B : Set b} → Vec A n → Vec B m → Vec (A × B) (n ⊓ m)
zipVec [] _ = []
zipVec (_ ∷ _) [] = []
zipVec (x ∷ xs) (y ∷ ys) = (x , y) ∷ zipVec xs ys
Sometimes pattern matching doesn't help though.
The question: But I wonder, whether something like that functions is already in agda-stdlib? And is there something like hoogle for Agda, or something like SearchAbout?
I don't think there is exactly your coerce function. However, it's a special case of a more general function - subst (the substitutive property of equality) from Relation.Binary.PropositionalEquality:
subst : ∀ {a p} {A : Set a} (P : A → Set p) {x y : A}
→ x ≡ y → P x → P y
subst P refl p = p
If you choose P = id (from Data.Function, or just write λ x → x), you get:
coerce : ∀ {ℓ} {A B : Set ℓ} → A ≡ B → A → B
coerce = subst id
By the way, the most likely reason you won't find this function predefined, is that Agda deals with coerces like that through rewrite:
postulate
n⊓0≡0 : ∀ n → n ⊓ 0 ≡ 0
zipVec : ∀ {a b n m} {A : Set a} {B : Set b}
→ Vec A n → Vec B m → Vec (A × B) (n ⊓ m)
zipVec [] _ = []
zipVec {n = n} _ [] rewrite n⊓0≡0 n = []
zipVec (x ∷ xs) (y ∷ ys) = (x , y) ∷ zipVec xs ys
This is a syntactic sugar for the more complicated:
zipVec {n = n} _ [] with n ⊓ 0 | n⊓0≡0 n
... | ._ | refl = []
If you are familiar with how with works, try to figure out how rewrite works; it's quite enlightening.

Applying rules in Agda

I am new to Agda, and I think I still have a problem to think in that paradigm. Here is my question..
I have a type monoid and a type Group implemented as follows:
record Monoid : Set₁ where
constructor monoid
field Carrier : Set
_⊙_ : Carrier → Carrier → Carrier
e : Carrier
leftId : ∀ {x : Carrier} → (e ⊙ x) ≡ x
rightId : ∀ {x : Carrier} → (x ⊙ e) ≡ x
assoc : ∀ {x y z : Carrier} → (x ⊙ (y ⊙ z)) ≡ ((x ⊙ y) ⊙ z)
record Group : Set₁ where
constructor group
field m : Monoid
inv : Carrier → Carrier
inverse1 : {x y : Carrier} → x ⊙ (inv x) ≡ e
inverse2 : {x y : Carrier} → (inv x) ⊙ x ≡ e
Now, I want to proof the following lemma :
lemma1 : (x y : Carrier) → (inv x) ⊙ (x ⊙ y) ≡ y
lemma1 x y = ?
If I do it on paper, I will apply associativity then left identity.. but I do not know how to tell agda to apply these rules.. I have the problem of translating my thoughts to the Agda paradigm..
Any help is highly appreciated..
When you do the proof on the paper, applying associativity and then left identity uses ony key property of the identity relation - transitivity. That is, when you have a proof of p : x ≡ y and q : y ≡ z you can combine them into a single proof of trans p q : x ≡ z. The trans function is already part of the standard library (Relation.Binary.PropositionalEquality module), but its implementation is fairly simple anyways:
trans : {A : Set} {i j k : A} → i ≡ j → j ≡ k → i ≡ k
trans refl eq = eq
I'm using a bit different presentation of monoids and groups, but you can easily adapt the proof to your scenario.
open import Function
open import Relation.Binary.PropositionalEquality
Op₁ : Set → Set
Op₁ A = A → A
Op₂ : Set → Set
Op₂ A = A → A → A
record IsMonoid {A : Set}
(_∙_ : Op₂ A) (ε : A) : Set where
field
right-id : ∀ x → x ∙ ε ≡ x
left-id : ∀ x → ε ∙ x ≡ x
assoc : ∀ x y z → x ∙ (y ∙ z) ≡ (x ∙ y) ∙ z
record IsGroup {A : Set}
(_∙_ : Op₂ A) (ε : A) (_⁻¹ : Op₁ A) : Set where
field
monoid : IsMonoid _∙_ ε
right-inv : ∀ x → x ∙ x ⁻¹ ≡ ε
left-inv : ∀ x → x ⁻¹ ∙ x ≡ ε
open IsMonoid monoid public
(To keep things simple, indented code is written as part of the IsGroup record). We'd like to prove that:
lemma : ∀ x y → x ⁻¹ ∙ (x ∙ y) ≡ y
lemma x y = ?
The first step is to use associativity, that is assoc (x ⁻¹) x y, this leaves us with a goal (x ⁻¹ ∙ x) ∙ y ≡ y - once we prove that, we can merge these two parts together using trans:
lemma x y =
trans (assoc (x ⁻¹) x y) ?
Now, we need to apply the right inverse property, but the types don't seem to fit. We have left-inv x : x ⁻¹ ∙ x ≡ ε and we need to somehow deal with the extra y. This is when another property of the identity comes into play.
Ordinary functions preserve identity; if we have a function f and a proof p : x ≡ y we can apply f to both x and y and the proof should be still valid, that is cong f p : f x ≡ f y. Again, implementation is already in the standard library, but here it is anyways:
cong : {A : Set} {B : Set}
(f : A → B) {x y} → x ≡ y → f x ≡ f y
cong f refl = refl
What function should we apply? Good candidate seems to be λ z → z ∙ y, which adds the missing y part. So, we have:
cong (λ z → z ∙ y) (left-inv x) : (x ⁻¹ ∙ x) ∙ y ≡ ε ∙ y
Again, we just need to prove that ε ∙ y ≡ y and we can then piece those together using trans. But this last property is easy, it's just left-id y. Putting it all together, we get:
lemma : ∀ x y → x ⁻¹ ∙ (x ∙ y) ≡ y
lemma x y =
trans (assoc (x ⁻¹) x y) $
trans (cong (λ z → z ∙ y) (left-inv x)) $
(left-id y)
Standard library also gives us some nice syntactic sugar for this:
open ≡-Reasoning
lemma′ : ∀ x y → x ⁻¹ ∙ (x ∙ y) ≡ y
lemma′ x y = begin
x ⁻¹ ∙ (x ∙ y) ≡⟨ assoc (x ⁻¹) x y ⟩
(x ⁻¹ ∙ x) ∙ y ≡⟨ cong (λ z → z ∙ y) (left-inv x) ⟩
ε ∙ y ≡⟨ left-id y ⟩
y ∎
Behind the scenes, ≡⟨ ⟩ uses precisely trans to merge those proofs. The types are optional (the proofs themselves carry enough information about them), but they are here for readability.
To get your original Group record, we can do something like:
record Group : Set₁ where
field
Carrier : Set
_∙_ : Op₂ Carrier
ε : Carrier
_⁻¹ : Op₁ Carrier
isGroup : IsGroup _∙_ ε _⁻¹
open IsGroup isGroup public

Resources