// Adapted from https://www.aya-prover.org/guide/prover-tutorial.html
// For syntax, see
// - https://github.com/aya-prover/aya-dev/blob/main/parser/src/main/grammar/AyaPsiLexer.flex
// - https://github.com/aya-prover/aya-dev/blob/main/parser/src/main/grammar/AyaPsiParser.bnf
prim I
prim coe (r s : I) (A : I → Type) : A r → A s
prim Path (A : I → Type) (a : A 0) (b : A 1) : Type
variable A B : Type // A : Type 0
// I: 0 = 1
// Path :
// 0 ↦ a : A
// 1 ↦ b : A
//
def infix = (a b : A) ⇒ Path (fn i ⇒ A) /* I → Type 0*/ a b
open inductive Nat
| zero
| suc Nat
open inductive Bool | true | false
def not Bool : Bool
| true ⇒ false
| false ⇒ true
def id (x : Bool) ⇒ x
def Goal ⇒ id = (fn x ⇒ not (not x))
// def question : Goal => {??}
def Goal' (x : Bool) ⇒ id x = not (not x)
def funExt (f g : A → B) (p : ∀ a → f a = g a /* Fn (y : ?_2 A B f g) → f y = g y */) : f = g /* I -> (A -> B) */
⇒ fn i a ⇒ p a i
def refl {a : A} : a = a ⇒ fn i ⇒ a
def pmap (f : A → B) {a b : A} (p : a = b) : f a = f b
⇒ fn i ⇒ f (p i)
/*
coe (r s : I) (A : I -> Type) : A r -> A s
r: 0
s: 1
A r ↦ A 0 ↦ p 0 ↦ A
A s ↦ A 1 ↦ p 1 ↦ B
cast A to B using A ↑= B
*/
def cast (p : A ↑ = B) : A → B ⇒ ↑ coe 0 1 (fn i ⇒ p i)
// ↑ is ulift
def cast' (p : A ↑ = B) : A → B ⇒ (↑ coe) 0 1 (fn i ⇒ p i)
/*
cast
?A A a b p
?A A a b p = (b = a)
*/
// def pinv {a b : A} (p : a = b) : b = a ⇒ cast {??} {??}
/*
Error: Cannot check the expression
cast (\ i ⇒ p i = b) refl
of type
b = b
against the type
b = a
In particular, we failed to unify
b
with
a
*/
// def pinv {a b : A} (p : a = b) : b = a ⇒ cast (fn i ⇒ p i = b) refl
/*
Error: Cannot check the expression
p
of type
a = b
against the type
a = a
In particular, we failed to unify
b
with
a
*/
// def pinv {a b : A} (p : a = b) : b = a ⇒ cast (fn i ⇒ p i = a) p
/*
Error: Cannot check the expression
cast (\ i ⇒ p i = b)
of type
(a = b) → b = b
against the type
(a = a) = (b = a)
*/
// def pinv_pre {a b : A} (p : a = b) : (a = a) = (b = a) => cast (fn i => p i = b)
def pinv {a b : A} (p : a = b) : b = a ⇒ cast (fn i ⇒ p i = a) refl
def concat {a b c : A} (p : a = b) (q : b = c) : a = c ⇒ cast (fn i ⇒ a = q i) p
example def infix + Nat Nat : Nat
| 0, n ⇒ n
| suc m, n ⇒ suc (m + n)
overlap def infix + Nat Nat : Nat
| 0, n ⇒ n
| n, 0 ⇒ n
| suc m, n ⇒ suc (m + n)
| m, suc n ⇒ suc (m + n)
tighter =
def +-comm' (a b : Nat) : a + b = b + a
| _, 0 ⇒ refl
| _, suc _ ⇒ pmap suc (+-comm' _ _)
def +-comm (a b : Nat) : a + b = b + a elim a
| 0 ⇒ refl
| suc _ ⇒ pmap suc (+-comm _ _)
def +-assoc' (a b c : Nat) : (a + b) + c = a + (b + c)
| 0, _, _ ⇒ refl
| suc a', b', c' ⇒ pmap suc (+-assoc' a' b' c')
def +-assoc {a b c : Nat} : (a + b) + c = a + (b + c) elim a
| 0 ⇒ refl
| suc _ ⇒ pmap suc +-assoc
variable n m o : Nat
// Definitions
open inductive Vec (Nat) (Type)
| 0, A ⇒ nil
| suc n, A ⇒ infixr :< A (Vec n A)
overlap def infixr ++ (Vec n A) (Vec m A) : Vec (n + m) A
| nil, ys ⇒ ys
| ys, nil ⇒ ys
| x :< xs, ys ⇒ x :< xs ++ ys
tighter :< =
/*
Error: Cannot check the expression
xs ++ (ys ++ zs)
of type
Vec (n + (m + o)) A
against the type
Vec ((n + m) + o) A
In particular, we failed to unify
n + (m + o)
with
(n + m) + o
1 error(s), 0 warning(s).
*/
// example def ++-assoc-ty' (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
// ⇒ ((xs ++ ys) ++ zs) = xs ++ (ys ++ zs)
// This is the original example
example def ++-assoc-ty (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
⇒ cast (↑ pmap (fn n ⇒ Vec n A) +-assoc) ((xs ++ ys) ++ zs) = xs ++ (ys ++ zs)
// This is after properly adding parenthesis, and one ulift is actually unnecessary
example def ++-assoc-ty'' (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
⇒ (cast // def cast (p : A ↑ = B) : A → B
(/* ↑ */ pmap (fn n ⇒ Vec n A) +-assoc) // (n + m) + o = m + (n + o) --pmap-> Vec ((n + m) + o) A = Vec (m + (n + o)) A
((xs ++ ys) ++ zs)
)
= xs ++ (ys ++ zs)
def coeRefl (a : A) : ((coe 1 1 (fn j ⇒ A)) a) = a ⇒ refl
def coeRefl' (a : A) : ((coe 0 0 (fn j ⇒ A)) a) = a ⇒ refl
// def coeRefl'' (a : A) : ((coe 0 1 (fn j ⇒ A)) a) = a ⇒ refl
// original
def castRefl (a : A) : cast ↑ refl a = a ⇒ fn i ⇒ coe i 1 (fn j ⇒ A) a
// break down
def castRefl' (a : A) : (cast (↑ refl) a) = a ⇒
/*
p: (cast (↑ refl) a) = a
p 0: (cast (↑ refl) a)
p 1: a
*/
fn i ⇒
/*
coe (r s : I) (p : I -> Type) : p r -> p s
r: i
s: 1
p r ↦ p i
p s ↦ p 1 ↦ a
cast A to A using A ↑= A
*/
(coe i 1 (fn j ⇒ A)) a
def castRefl'' (a : A) : a = (cast (↑ refl) a) ⇒
fn i ⇒
/*
coe (r s : I) (A : I -> Type) : A r -> A s
r: i
s: 1
A r ↦ A i ↦ A
A s ↦ A 1 ↦ A
cast A to A using A ↑= A
*/
(coe 0 i (fn j ⇒ A)) a
def Path' (A : I → Type) (a : A 0) (b : A 1) ⇒ Path A a b
def ++-assoc-type (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
⇒ Path (fn i ⇒ Vec (+-assoc i) A) ((xs ++ ys) ++ zs) (xs ++ (ys ++ zs))
/*
overlap def infixr ++ (Vec n A) (Vec m A) : Vec (n + m) A
| nil, ys ⇒ ys
| ys, nil ⇒ ys
| x :< xs, ys ⇒ x :< xs ++ ys
tighter :< =
*/
def ++-assoc (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
: Path (fn i ⇒ Vec (+-assoc i) A) ((xs ++ ys) ++ zs) (xs ++ (ys ++ zs)) elim xs
| nil ⇒ refl
| x :< _ ⇒
fn i ⇒ x :< ((++-assoc _ _ _) i)
// def ++-assoc' (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
// : Path (fn i ⇒ Vec (+-assoc i) A) ((xs ++ ys) ++ zs) (xs ++ (ys ++ zs)) elim xs
// | nil ⇒ refl
// | x :< _ => pmap (x :<) (++-assoc' _ _ _)
open inductive Interval
| left
| right
| line : left = right
example def Interval-elim {a b : A} {p : a = b} (i : Interval) : A elim i
| left ⇒ a
| right ⇒ b
| line j ⇒ p j
private def lemma
(f g : A → B) (p : ∀ x → f x = g x)
(i : Interval) (a : A) : B elim i
| left ⇒ f a
| right ⇒ g a
| line j ⇒ p a j
example def funExt' (f g : A → B) (p : ∀ a → f a = g a) : f = g ⇒
pmap (lemma f g p) (fn i ⇒ line i)
open inductive Int
| pos Nat | neg Nat
| zro : pos 0 = neg 0
def succ Int : Int
| pos n ⇒ pos (suc n)
| neg 0 ⇒ pos 1
| neg (suc n) ⇒ neg n
| zro i ⇒ pos 1
def abs Int : Nat
| pos n ⇒ n
| neg n ⇒ n
| zro _ ⇒ 0