We have designed a binary operator system in Aya which happens to be (we didn't copy!) very similar to Rhombus (a.k.a. Racket 2) and Swift 5.7.
TL;DR: it supports making any identifier a custom operator with precedences specified by a partial ordering. Left and right associativities are supported.
The precedence and associativity information is bound to a name, not a definition. This means we can import a name from another module with changes to its name, associativity, and precedence. Importing with renaming is an established feature, but changing associativity and precedence is not that popular (though implemented in Agda already).
Here are some code examples (implementations are omitted for simplicity):
The tighter keyword works like this: when there are expressions like a * b + c which may either mean (a * b) + c or a * (b + c), we will put the tighter operator in the parenthesis. In case we found the two operators share the same priority, Aya will report an error.
With imports, it looks like this:
open import Primitives using (
+ invol as fixl ~ tighter =, \\/, /\\,
+ intervalMin as infix /\\ tighter \\/,
+ intervalMax as infix \\/,
+)
Specifying operator precedences with a partial ordering is way better than with a number. In Haskell, if we already have infix 3 + and infix 4 * and we hope to add a new operator which has higher precedence than + but lower than *, it's going to be impossible. Agda introduced float-point precedence levels to address the issue, but I think it does not solve the essential problem: that I have to lookup the numbers (of existing operator precedences) every time I write a new operator.
In the future, we plan to support mixfix operators as in Agda (the current framework can support mixfix easily, but abusing mixfix notations can harm readability).
`,11)]))}const f=a(i,[["render",o]]);export{m as __pageData,f as default};
diff --git a/assets/blog_binops.md.BnuGOt04.lean.js b/assets/blog_binops.md.BnuGOt04.lean.js
new file mode 100644
index 0000000..7641d3c
--- /dev/null
+++ b/assets/blog_binops.md.BnuGOt04.lean.js
@@ -0,0 +1,12 @@
+import{_ as a,c as t,a2 as n,o as s}from"./chunks/framework.BnE-uSbk.js";const m=JSON.parse('{"title":"Binary operators in Aya","description":"","frontmatter":{},"headers":[],"relativePath":"blog/binops.md","filePath":"blog/binops.md","lastUpdated":1717413547000}'),i={name:"blog/binops.md"};function o(r,e,p,c,l,d){return s(),t("div",null,e[0]||(e[0]=[n(`
We have designed a binary operator system in Aya which happens to be (we didn't copy!) very similar to Rhombus (a.k.a. Racket 2) and Swift 5.7.
TL;DR: it supports making any identifier a custom operator with precedences specified by a partial ordering. Left and right associativities are supported.
The precedence and associativity information is bound to a name, not a definition. This means we can import a name from another module with changes to its name, associativity, and precedence. Importing with renaming is an established feature, but changing associativity and precedence is not that popular (though implemented in Agda already).
Here are some code examples (implementations are omitted for simplicity):
The tighter keyword works like this: when there are expressions like a * b + c which may either mean (a * b) + c or a * (b + c), we will put the tighter operator in the parenthesis. In case we found the two operators share the same priority, Aya will report an error.
With imports, it looks like this:
open import Primitives using (
+ invol as fixl ~ tighter =, \\/, /\\,
+ intervalMin as infix /\\ tighter \\/,
+ intervalMax as infix \\/,
+)
Specifying operator precedences with a partial ordering is way better than with a number. In Haskell, if we already have infix 3 + and infix 4 * and we hope to add a new operator which has higher precedence than + but lower than *, it's going to be impossible. Agda introduced float-point precedence levels to address the issue, but I think it does not solve the essential problem: that I have to lookup the numbers (of existing operator precedences) every time I write a new operator.
In the future, we plan to support mixfix operators as in Agda (the current framework can support mixfix easily, but abusing mixfix notations can harm readability).
`,11)]))}const f=a(i,[["render",o]]);export{m as __pageData,f as default};
diff --git a/assets/blog_bye-hott.md.NGE4GKmU.js b/assets/blog_bye-hott.md.NGE4GKmU.js
new file mode 100644
index 0000000..2c522e7
--- /dev/null
+++ b/assets/blog_bye-hott.md.NGE4GKmU.js
@@ -0,0 +1 @@
+import{_ as t,c as a,a2 as i,o}from"./chunks/framework.BnE-uSbk.js";const d=JSON.parse('{"title":"Moving away from univalent type theory","description":"","frontmatter":{},"headers":[],"relativePath":"blog/bye-hott.md","filePath":"blog/bye-hott.md","lastUpdated":1710300019000}'),n={name:"blog/bye-hott.md"};function s(r,e,l,p,c,h){return o(),a("div",null,e[0]||(e[0]=[i('
Aya is now moving away from univalent type theory.
Note that this does not mean we are moving away from cubical type theory -- we are trying to adapt an extensional version cubical type theory, called XTT, which is a cubical approach towards observational equality (the idea is due to Altenkirch and McBride): the equality type a =_A b is no longer defined uniformly for all types A, but rather defined by assuming a closed (inductive-recursive) universe, and defining a type family (A : Type) -> A -> A -> Type by casing on what A is. For function types, we can define it as pointwise equality, which makes function extensionality true by definition.
In case of cubical, this is automatic, due to how path types are defined.
The reference for XTT can be found in the paper A Cubical Language for Bishop Sets by Sterling, Angiuli, and Gratzer. This paper has a previous version which has a universe hierarchy, called Cubical Syntax for Reflection-Free Extensional Equality, by the same authors.
We plan to use XTT as the basis for Aya's type theory. We will change the following in v0.30 Aya:
We will implement a universe à la Tarski to reuse the type checking of subtypes and paths.
The impredicative Prop universe will be removed due to the complications it caused.
The binding representation will be changed to locally nameless. By that we can make closed term completely serializable.
We will try to implement definition-level controlling unfolding. This has a several advantages: the type checking order of bodies can be inferred from the annotations, and we can detect more cycles instead of reporting errors due to not being able to unfold unchecked function.
We wish to remove implicitness information from core terms, and keep them a feature related to function calls. Π-types should not know the name of the parameter, which is natural due to α-equality. This means named arguments will only work for direct function calls.
Yes, the last two items indicate a major change in the implementation of Aya, which is essentially a rewrite of the type checker. We took this chance to revisit a couple of old issues and fix them. Currently, we have suceeded in extracting a Java module for the syntax definition from the type checker module, which will benefit third-party libraries who want to deal with serialized Aya terms.
We will not adapt the following features from XTT:
Partial elements are first-class citizens, i.e. they have manifest "cubical" phases. Instead we will have first class total elements and use a Partial type to represent partial elements.
Intervals are not types. We will adapt the 2LTT-style solution from Cubical Agda, which has some universes to classify exo-types.
The type-case operator will remain internal to the type checker. While this might be useful in the future development related to metaprogramming, we do not see any immediate use for it except for implementing the computation of generalized coercion.
As we already said, we do not intend to add an impredicative Prop universe, while the XTT paper said they intend to add it. We encourage the users to embrace the axiom of propositional resizing, which makes not just Props to be impredicative, but also all h-props (e.g. types that are provably props) to be impredicative.
The development is still in a private work-in-progress repository, which we will open-source and be ported to the main repo once we can compile this website with the new type checker, which implies complete support for inductive types except for the positivity checker.
We will also have to rewrite some guides about higher inductive types, and instead use some quotient type examples.
From that, we will start considering support for classes with extensions, and try to formalize some mathematics and do some real-world programming with Aya, partially bootstrapping the type checker.
Stay tuned!
',14)]))}const u=t(n,[["render",s]]);export{d as __pageData,u as default};
diff --git a/assets/blog_bye-hott.md.NGE4GKmU.lean.js b/assets/blog_bye-hott.md.NGE4GKmU.lean.js
new file mode 100644
index 0000000..2c522e7
--- /dev/null
+++ b/assets/blog_bye-hott.md.NGE4GKmU.lean.js
@@ -0,0 +1 @@
+import{_ as t,c as a,a2 as i,o}from"./chunks/framework.BnE-uSbk.js";const d=JSON.parse('{"title":"Moving away from univalent type theory","description":"","frontmatter":{},"headers":[],"relativePath":"blog/bye-hott.md","filePath":"blog/bye-hott.md","lastUpdated":1710300019000}'),n={name:"blog/bye-hott.md"};function s(r,e,l,p,c,h){return o(),a("div",null,e[0]||(e[0]=[i('
Aya is now moving away from univalent type theory.
Note that this does not mean we are moving away from cubical type theory -- we are trying to adapt an extensional version cubical type theory, called XTT, which is a cubical approach towards observational equality (the idea is due to Altenkirch and McBride): the equality type a =_A b is no longer defined uniformly for all types A, but rather defined by assuming a closed (inductive-recursive) universe, and defining a type family (A : Type) -> A -> A -> Type by casing on what A is. For function types, we can define it as pointwise equality, which makes function extensionality true by definition.
In case of cubical, this is automatic, due to how path types are defined.
The reference for XTT can be found in the paper A Cubical Language for Bishop Sets by Sterling, Angiuli, and Gratzer. This paper has a previous version which has a universe hierarchy, called Cubical Syntax for Reflection-Free Extensional Equality, by the same authors.
We plan to use XTT as the basis for Aya's type theory. We will change the following in v0.30 Aya:
We will implement a universe à la Tarski to reuse the type checking of subtypes and paths.
The impredicative Prop universe will be removed due to the complications it caused.
The binding representation will be changed to locally nameless. By that we can make closed term completely serializable.
We will try to implement definition-level controlling unfolding. This has a several advantages: the type checking order of bodies can be inferred from the annotations, and we can detect more cycles instead of reporting errors due to not being able to unfold unchecked function.
We wish to remove implicitness information from core terms, and keep them a feature related to function calls. Π-types should not know the name of the parameter, which is natural due to α-equality. This means named arguments will only work for direct function calls.
Yes, the last two items indicate a major change in the implementation of Aya, which is essentially a rewrite of the type checker. We took this chance to revisit a couple of old issues and fix them. Currently, we have suceeded in extracting a Java module for the syntax definition from the type checker module, which will benefit third-party libraries who want to deal with serialized Aya terms.
We will not adapt the following features from XTT:
Partial elements are first-class citizens, i.e. they have manifest "cubical" phases. Instead we will have first class total elements and use a Partial type to represent partial elements.
Intervals are not types. We will adapt the 2LTT-style solution from Cubical Agda, which has some universes to classify exo-types.
The type-case operator will remain internal to the type checker. While this might be useful in the future development related to metaprogramming, we do not see any immediate use for it except for implementing the computation of generalized coercion.
As we already said, we do not intend to add an impredicative Prop universe, while the XTT paper said they intend to add it. We encourage the users to embrace the axiom of propositional resizing, which makes not just Props to be impredicative, but also all h-props (e.g. types that are provably props) to be impredicative.
The development is still in a private work-in-progress repository, which we will open-source and be ported to the main repo once we can compile this website with the new type checker, which implies complete support for inductive types except for the positivity checker.
We will also have to rewrite some guides about higher inductive types, and instead use some quotient type examples.
From that, we will start considering support for classes with extensions, and try to formalize some mathematics and do some real-world programming with Aya, partially bootstrapping the type checker.
Stay tuned!
',14)]))}const u=t(n,[["render",s]]);export{d as __pageData,u as default};
diff --git a/assets/blog_class-defeq.md.XvEV7HU1.js b/assets/blog_class-defeq.md.XvEV7HU1.js
new file mode 100644
index 0000000..48e6b44
--- /dev/null
+++ b/assets/blog_class-defeq.md.XvEV7HU1.js
@@ -0,0 +1,12 @@
+import{_ as s,c as e,a2 as t,o as n}from"./chunks/framework.BnE-uSbk.js";const h=JSON.parse('{"title":"Class extension with definitional projection","description":"","frontmatter":{},"headers":[],"relativePath":"blog/class-defeq.md","filePath":"blog/class-defeq.md","lastUpdated":1679761681000}'),o={name:"blog/class-defeq.md"};function i(p,a,l,c,r,m){return n(),e("div",null,a[0]||(a[0]=[t(`
Suppose we have a class Precat for precategories (written in pseudocode):
class Precat
+| Ob : Type
+| Hom : Ob -> Ob -> Type
+| Hom-set (A B : Ob) : isSet (Hom A B)
+| id (A : Ob) : Hom A A
+| ....
Suppose the syntax for creating an instance of a class is new Precat { Ob := .., Hom := .., ... }. I want the following:
Precat is the type for all instances of the class Precat.
Precat { Ob := Group } is the type for all instances of the class Precat whose Ob field is (definitionally) Group.
Precat { Ob := Group, Hom := GroupHom } is the type for all instances of the class Precat whose Ob field is Group and Hom field is GroupHom.
etc.
This is called anonymous class extension, already implemented in the Arend language. As a syntactic sugar, we may write Precat { Ob := Group } as Precat Group, where the application is ordered the same as the fields in the class definition.
Suppose A : Precat Group, then A.Ob is definitionally equal to Group.
Suppose A : Precat Group GroupHom, then A.Hom is definitionally equal to GroupHom.
This concludes the basic features of the class system. To implement this, it may seem that we need to have access to types in the normalizer, which makes it very heavy (in contrast to the lightweight normalizer you can have for plain MLTT).
A uniform implementation of this definitional projection requires the definitional equality to commute with substitution, say, we may have
A:Precat⊢A.Ob:U
This is a normal form. Then, we have Grp : Precat Group (so Grp.Ob is definitionally equal to Group), and we may perform the substitution [Grp/A] on the above normal form:
Grp:PrecatGroup⊢Grp.Ob:U
We want the above to be equal to Group as well. Without access to contexts, it seems really hard!
Here's a trick: whenever we see A : Precat Group, we elaborate it into (the idea is similar to an η-expansion):
A ==> new Precat
+ { Ob := Group
+ , Hom := A.Hom
+ , Hom-set := A.Hom-set
+ , id := A.id
+ , ...
+ }
By that, we will never have A.Ob in the source language, because it always gets elaborated into Group directly. In case we partially know about A from the type, we really elaborate the type information right into the core term. So, we don't even have a chance to touch the bare A (not being projected) in the core language, and anything of a class type is always in an introduction form.
This should implement the definitional projection feature without even modifying the MLTT normalizer.
The idea of this feature comes from the treatment of extension types inspired from cooltt, see relevant post.
`,25)]))}const u=s(o,[["render",i]]);export{h as __pageData,u as default};
diff --git a/assets/blog_class-defeq.md.XvEV7HU1.lean.js b/assets/blog_class-defeq.md.XvEV7HU1.lean.js
new file mode 100644
index 0000000..48e6b44
--- /dev/null
+++ b/assets/blog_class-defeq.md.XvEV7HU1.lean.js
@@ -0,0 +1,12 @@
+import{_ as s,c as e,a2 as t,o as n}from"./chunks/framework.BnE-uSbk.js";const h=JSON.parse('{"title":"Class extension with definitional projection","description":"","frontmatter":{},"headers":[],"relativePath":"blog/class-defeq.md","filePath":"blog/class-defeq.md","lastUpdated":1679761681000}'),o={name:"blog/class-defeq.md"};function i(p,a,l,c,r,m){return n(),e("div",null,a[0]||(a[0]=[t(`
Suppose we have a class Precat for precategories (written in pseudocode):
class Precat
+| Ob : Type
+| Hom : Ob -> Ob -> Type
+| Hom-set (A B : Ob) : isSet (Hom A B)
+| id (A : Ob) : Hom A A
+| ....
Suppose the syntax for creating an instance of a class is new Precat { Ob := .., Hom := .., ... }. I want the following:
Precat is the type for all instances of the class Precat.
Precat { Ob := Group } is the type for all instances of the class Precat whose Ob field is (definitionally) Group.
Precat { Ob := Group, Hom := GroupHom } is the type for all instances of the class Precat whose Ob field is Group and Hom field is GroupHom.
etc.
This is called anonymous class extension, already implemented in the Arend language. As a syntactic sugar, we may write Precat { Ob := Group } as Precat Group, where the application is ordered the same as the fields in the class definition.
Suppose A : Precat Group, then A.Ob is definitionally equal to Group.
Suppose A : Precat Group GroupHom, then A.Hom is definitionally equal to GroupHom.
This concludes the basic features of the class system. To implement this, it may seem that we need to have access to types in the normalizer, which makes it very heavy (in contrast to the lightweight normalizer you can have for plain MLTT).
A uniform implementation of this definitional projection requires the definitional equality to commute with substitution, say, we may have
A:Precat⊢A.Ob:U
This is a normal form. Then, we have Grp : Precat Group (so Grp.Ob is definitionally equal to Group), and we may perform the substitution [Grp/A] on the above normal form:
Grp:PrecatGroup⊢Grp.Ob:U
We want the above to be equal to Group as well. Without access to contexts, it seems really hard!
Here's a trick: whenever we see A : Precat Group, we elaborate it into (the idea is similar to an η-expansion):
A ==> new Precat
+ { Ob := Group
+ , Hom := A.Hom
+ , Hom-set := A.Hom-set
+ , id := A.id
+ , ...
+ }
By that, we will never have A.Ob in the source language, because it always gets elaborated into Group directly. In case we partially know about A from the type, we really elaborate the type information right into the core term. So, we don't even have a chance to touch the bare A (not being projected) in the core language, and anything of a class type is always in an introduction form.
This should implement the definitional projection feature without even modifying the MLTT normalizer.
The idea of this feature comes from the treatment of extension types inspired from cooltt, see relevant post.
`,25)]))}const u=s(o,[["render",i]]);export{h as __pageData,u as default};
diff --git a/assets/blog_extended-pruning.md.CuhyEVbT.js b/assets/blog_extended-pruning.md.CuhyEVbT.js
new file mode 100644
index 0000000..a757619
--- /dev/null
+++ b/assets/blog_extended-pruning.md.CuhyEVbT.js
@@ -0,0 +1,51 @@
+import{_ as z,c as w,j as s,a as e,a2 as V,o as _}from"./chunks/framework.BnE-uSbk.js";const C={mounted(){const h=new Map;function d(l){const a=l.querySelectorAll("a[href]");for(const n of a){const o=n.href,r=h.get(o)??new Set;r.add(n),h.set(o,r)}for(const n of a)n.onmouseover=function(){for(const o of h.get(this.href))o.classList.add("hover-highlight")},n.onmouseout=function(){for(const o of h.get(this.href))o.classList.remove("hover-highlight")}}function y(l){return decodeURIComponent(atob(l).split("").map(function(a){return"%"+("00"+a.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const f=(l=>{const a={};return(...n)=>{const o=JSON.stringify(n);return a[o]=a[o]||l(...n)}})(y);class m{constructor(){this.list=[]}dismiss(a){a&&(a.remove(),this.list=this.list.filter(n=>n!==a))}dismissIfNotUsed(a){a&&(a.markedForDismissal=!0,setTimeout(()=>{!a.userIsThinking&&this.allowAutoDismissal(a)&&this.dismiss(a)},1e3))}allowAutoDismissal(a){return a.markedForDismissal&&!a.userClicked}fireAutoDismissalFor(a){let n=this.list.find(o=>o.userCreatedFrom===a);this.dismissIfNotUsed(n)}createHoverFor(a,n,o){let r=this.list.find(i=>i.userCreatedFrom===a);if(r&&r.userClicked)return r;let b=[];const x=this.list.filter(i=>{if(this.allowAutoDismissal(i))return b.push(i),!1;const p=i.userCreatedFrom,u=a;let c=u;for(;c;){if(c===p)return!0;c=c.parentElement}for(c=p;c;){if(c===u)return!0;c=c.parentElement}return!1});b.forEach(i=>this.dismiss(i));let t=document.createElement("div");t.userCreatedFrom=a,t.innerHTML="×"+f(n),t.classList.add("AyaTooltipPopup"),d(t);let A=this;if(t.handleEvent=function(i){if(i.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let p=this.children[0];if(!p)return;let u=this;p.style.visibility="visible",p.addEventListener("click",c=>A.dismiss(u))}i.type==="mouseover"&&(this.userIsThinking=!0),i.type==="mouseout"&&(this.userIsThinking=!1,A.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),o.appendChild(t),t.style.left=`${a.offsetLeft}px`,x.length===0){const i=a.getBoundingClientRect(),p=t.getBoundingClientRect();i.bottom+p.height+30>window.innerHeight?t.style.top=`calc(${a.offsetTop-p.height+8}px - 3em)`:t.style.top=`${a.offsetTop+a.offsetHeight+8}px`}else{const i=Math.max(...x.map(p=>p.offsetTop+p.offsetHeight));t.style.top=`${i+8}px`}return this.list.push(t),t}}let v=new m;function g(l){return function(){let a=this;const n=a.getAttribute("data-tooltip-text");n&&(l?v.createHoverFor(a,n,document.body):v.fireAutoDismissalFor(a))}}d(document);{let l=document.getElementsByClassName("aya-tooltip");for(let a=0;aThis is the equality between two sized vectors: (xs ++ (ys ++ zs)) and ((xs ++ ys) ++ zs), the left hand side has type Vec (xs.size ++ (ys.size ++ zs.size)) A, and the right hand side has type Vec ((xs.size ++ ys.size) ++ zs.size).
So, the equality type is heterogeneous, and I introduce a type Vec (+-assoc i) A for it, where +-assoc is the associativity.
So this should type check, right? But pattern unification fails! I've left the two sides of +-assoc implicit, so I'm supposed to infer what numbers' associativity I care about, using pattern unification.
Then, pattern unification fails because the constraints are generated from cubical boundaries, where the "interval" variable is substituted to its sides. So, we have this type (the Path is called PathP in Agda):
Look at the spines of all of these metavariables. None of them are in pattern fragment. So every equality constraint cannot be solved by pattern, because they're always equality after a substitution!
This can be solved by further extending your algorithm with pruning or a constraint system with a "lax" mode of solving metas when your equations rely essentially on non-pattern equations, but I feel it has defeated the point of finding the most general solution, which I used to believe to be the purpose of pattern unification....
Right now Aya will try to prune these non-pattern arguments out and try to solve them. This obviously generates non-unique solutions, but I think it will be useful in practice.
In Agda, the following code is in the library:
++-assoc : ∀ {m n k} (xs : Vec A m) (ys : Vec A n) (zs : Vec A k) →
+ PathP (λ i → Vec A (+-assoc m n k (~ i)))
+ ((xs ++ ys) ++ zs) (xs ++ ys ++ zs)
+++-assoc {m = zero} [] ys zs = refl
+++-assoc {m = suc m} (x ∷ xs) ys zs i = x ∷ ++-assoc xs ys zs i
However, if we replace the m with _, Agda will fail with the following error:
Failed to solve the following constraints:
+ _41 (xs = (x ∷ xs)) (ys = ys) (zs = zs) = x ∷ ++-assoc xs ys zs i1
+ : Vec A
+ (+-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i1)) n k
+ (~ i1))
+ (blocked on any(_41, _57))
+ _40 (xs = (x ∷ xs)) (ys = ys) (zs = zs) = x ∷ ++-assoc xs ys zs i0
+ : Vec A
+ (+-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i0)) n k
+ (~ i0))
+ (blocked on any(_40, _57))
+ +-assoc (_m_39 (xs = xs) (ys = ys) (zs = zs) (i = i)) n k (~ i)
+ = _n_49
+ : ℕ
+ (blocked on _n_49)
+ +-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i)) n k
+ (~ i)
+ = ℕ.suc _n_49
+ : ℕ
+ (blocked on _m_39)
+ _40 (xs = []) (ys = ys) (zs = zs)
+ = _41 (xs = []) (ys = ys) (zs = zs)
+ : _x.A_43
+ (blocked on any(_40, _41))
+ _x.A_43
+ = Vec A
+ (+-assoc (_m_39 (xs = []) (ys = ys) (zs = zs) (i = i)) n k (~ i))
+ : Type
+ (blocked on _x.A_43)
+ _m_39 (i = i0) = m : ℕ (blocked on _m_39)
+ _m_39 (i = i1) + (n + k) = m + (n + k) : ℕ (blocked on _m_39)
In Aya, this will raise the following warning:
6 │ def ++-assoc-type (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
+ 7 │ => Path (fn i => Vec (+-assoc i) A)
+ 8 │ (xs ++ (ys ++ zs))
+ │ ╰──────────────╯ ?a n A m o xs ys zs 0 >= n, ?b n A m o xs ys zs 0 >= m,
+ ?c n A m o xs ys zs 0 >= o
+ 9 │ ((xs ++ ys) ++ zs)
+ │ ╰──────────────╯
+ │ ╰──────────────╯ ?a n A m o xs ys zs 1 >= n, ?b n A m o xs ys zs 1 >= m,
+ ?c n A m o xs ys zs 1 >= o
+
+Info: Solving equation(s) with not very general solution(s)
The inline equations are the type checking problems that Aya did something bad to solve.
Conor McBride told me pattern unification is a good algorithm, but the problem of interest might not be what we think it is. It is good for undergraduate induction, i.e. the object being induct on is a variable, and the motive of such induction is pattern. This is an enlightening perspective! But now that we have more problems, I think we might want to extend it. Just think about how many people use --lossy-unification in Agda.
`,26)]))}const P=z(C,[["render",L]]);export{I as __pageData,P as default};
diff --git a/assets/blog_extended-pruning.md.CuhyEVbT.lean.js b/assets/blog_extended-pruning.md.CuhyEVbT.lean.js
new file mode 100644
index 0000000..a757619
--- /dev/null
+++ b/assets/blog_extended-pruning.md.CuhyEVbT.lean.js
@@ -0,0 +1,51 @@
+import{_ as z,c as w,j as s,a as e,a2 as V,o as _}from"./chunks/framework.BnE-uSbk.js";const C={mounted(){const h=new Map;function d(l){const a=l.querySelectorAll("a[href]");for(const n of a){const o=n.href,r=h.get(o)??new Set;r.add(n),h.set(o,r)}for(const n of a)n.onmouseover=function(){for(const o of h.get(this.href))o.classList.add("hover-highlight")},n.onmouseout=function(){for(const o of h.get(this.href))o.classList.remove("hover-highlight")}}function y(l){return decodeURIComponent(atob(l).split("").map(function(a){return"%"+("00"+a.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const f=(l=>{const a={};return(...n)=>{const o=JSON.stringify(n);return a[o]=a[o]||l(...n)}})(y);class m{constructor(){this.list=[]}dismiss(a){a&&(a.remove(),this.list=this.list.filter(n=>n!==a))}dismissIfNotUsed(a){a&&(a.markedForDismissal=!0,setTimeout(()=>{!a.userIsThinking&&this.allowAutoDismissal(a)&&this.dismiss(a)},1e3))}allowAutoDismissal(a){return a.markedForDismissal&&!a.userClicked}fireAutoDismissalFor(a){let n=this.list.find(o=>o.userCreatedFrom===a);this.dismissIfNotUsed(n)}createHoverFor(a,n,o){let r=this.list.find(i=>i.userCreatedFrom===a);if(r&&r.userClicked)return r;let b=[];const x=this.list.filter(i=>{if(this.allowAutoDismissal(i))return b.push(i),!1;const p=i.userCreatedFrom,u=a;let c=u;for(;c;){if(c===p)return!0;c=c.parentElement}for(c=p;c;){if(c===u)return!0;c=c.parentElement}return!1});b.forEach(i=>this.dismiss(i));let t=document.createElement("div");t.userCreatedFrom=a,t.innerHTML="×"+f(n),t.classList.add("AyaTooltipPopup"),d(t);let A=this;if(t.handleEvent=function(i){if(i.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let p=this.children[0];if(!p)return;let u=this;p.style.visibility="visible",p.addEventListener("click",c=>A.dismiss(u))}i.type==="mouseover"&&(this.userIsThinking=!0),i.type==="mouseout"&&(this.userIsThinking=!1,A.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),o.appendChild(t),t.style.left=`${a.offsetLeft}px`,x.length===0){const i=a.getBoundingClientRect(),p=t.getBoundingClientRect();i.bottom+p.height+30>window.innerHeight?t.style.top=`calc(${a.offsetTop-p.height+8}px - 3em)`:t.style.top=`${a.offsetTop+a.offsetHeight+8}px`}else{const i=Math.max(...x.map(p=>p.offsetTop+p.offsetHeight));t.style.top=`${i+8}px`}return this.list.push(t),t}}let v=new m;function g(l){return function(){let a=this;const n=a.getAttribute("data-tooltip-text");n&&(l?v.createHoverFor(a,n,document.body):v.fireAutoDismissalFor(a))}}d(document);{let l=document.getElementsByClassName("aya-tooltip");for(let a=0;aThis is the equality between two sized vectors: (xs ++ (ys ++ zs)) and ((xs ++ ys) ++ zs), the left hand side has type Vec (xs.size ++ (ys.size ++ zs.size)) A, and the right hand side has type Vec ((xs.size ++ ys.size) ++ zs.size).
So, the equality type is heterogeneous, and I introduce a type Vec (+-assoc i) A for it, where +-assoc is the associativity.
So this should type check, right? But pattern unification fails! I've left the two sides of +-assoc implicit, so I'm supposed to infer what numbers' associativity I care about, using pattern unification.
Then, pattern unification fails because the constraints are generated from cubical boundaries, where the "interval" variable is substituted to its sides. So, we have this type (the Path is called PathP in Agda):
Look at the spines of all of these metavariables. None of them are in pattern fragment. So every equality constraint cannot be solved by pattern, because they're always equality after a substitution!
This can be solved by further extending your algorithm with pruning or a constraint system with a "lax" mode of solving metas when your equations rely essentially on non-pattern equations, but I feel it has defeated the point of finding the most general solution, which I used to believe to be the purpose of pattern unification....
Right now Aya will try to prune these non-pattern arguments out and try to solve them. This obviously generates non-unique solutions, but I think it will be useful in practice.
In Agda, the following code is in the library:
++-assoc : ∀ {m n k} (xs : Vec A m) (ys : Vec A n) (zs : Vec A k) →
+ PathP (λ i → Vec A (+-assoc m n k (~ i)))
+ ((xs ++ ys) ++ zs) (xs ++ ys ++ zs)
+++-assoc {m = zero} [] ys zs = refl
+++-assoc {m = suc m} (x ∷ xs) ys zs i = x ∷ ++-assoc xs ys zs i
However, if we replace the m with _, Agda will fail with the following error:
Failed to solve the following constraints:
+ _41 (xs = (x ∷ xs)) (ys = ys) (zs = zs) = x ∷ ++-assoc xs ys zs i1
+ : Vec A
+ (+-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i1)) n k
+ (~ i1))
+ (blocked on any(_41, _57))
+ _40 (xs = (x ∷ xs)) (ys = ys) (zs = zs) = x ∷ ++-assoc xs ys zs i0
+ : Vec A
+ (+-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i0)) n k
+ (~ i0))
+ (blocked on any(_40, _57))
+ +-assoc (_m_39 (xs = xs) (ys = ys) (zs = zs) (i = i)) n k (~ i)
+ = _n_49
+ : ℕ
+ (blocked on _n_49)
+ +-assoc (_m_39 (xs = (x ∷ xs)) (ys = ys) (zs = zs) (i = i)) n k
+ (~ i)
+ = ℕ.suc _n_49
+ : ℕ
+ (blocked on _m_39)
+ _40 (xs = []) (ys = ys) (zs = zs)
+ = _41 (xs = []) (ys = ys) (zs = zs)
+ : _x.A_43
+ (blocked on any(_40, _41))
+ _x.A_43
+ = Vec A
+ (+-assoc (_m_39 (xs = []) (ys = ys) (zs = zs) (i = i)) n k (~ i))
+ : Type
+ (blocked on _x.A_43)
+ _m_39 (i = i0) = m : ℕ (blocked on _m_39)
+ _m_39 (i = i1) + (n + k) = m + (n + k) : ℕ (blocked on _m_39)
In Aya, this will raise the following warning:
6 │ def ++-assoc-type (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
+ 7 │ => Path (fn i => Vec (+-assoc i) A)
+ 8 │ (xs ++ (ys ++ zs))
+ │ ╰──────────────╯ ?a n A m o xs ys zs 0 >= n, ?b n A m o xs ys zs 0 >= m,
+ ?c n A m o xs ys zs 0 >= o
+ 9 │ ((xs ++ ys) ++ zs)
+ │ ╰──────────────╯
+ │ ╰──────────────╯ ?a n A m o xs ys zs 1 >= n, ?b n A m o xs ys zs 1 >= m,
+ ?c n A m o xs ys zs 1 >= o
+
+Info: Solving equation(s) with not very general solution(s)
The inline equations are the type checking problems that Aya did something bad to solve.
Conor McBride told me pattern unification is a good algorithm, but the problem of interest might not be what we think it is. It is good for undergraduate induction, i.e. the object being induct on is a variable, and the motive of such induction is pattern. This is an enlightening perspective! But now that we have more problems, I think we might want to extend it. Just think about how many people use --lossy-unification in Agda.
`,26)]))}const P=z(C,[["render",L]]);export{I as __pageData,P as default};
diff --git a/assets/blog_ind-prop.md.BgOiB5U1.js b/assets/blog_ind-prop.md.BgOiB5U1.js
new file mode 100644
index 0000000..f36903a
--- /dev/null
+++ b/assets/blog_ind-prop.md.BgOiB5U1.js
@@ -0,0 +1,18 @@
+import{_ as a,c as i,a2 as s,o as t}from"./chunks/framework.BnE-uSbk.js";const k=JSON.parse('{"title":"Impredicative Props are hard","description":"","frontmatter":{},"headers":[],"relativePath":"blog/ind-prop.md","filePath":"blog/ind-prop.md","lastUpdated":1718905368000}'),n={name:"blog/ind-prop.md"};function o(p,e,r,l,h,d){return t(),i("div",null,e[0]||(e[0]=[s(`
Throughout this blog post, I will use the term Prop to mean the type of propositions, which does not have to be strict, but has the property that it cannot eliminate to Type.
Long time ago I wrote a PASE question regarding definitional irrelevance. An important pro of Prop in my opinion is that it is more convenient to be turned impredicative. Mathematicians want impredicativity for various reasons, one thing being that it is natural to have a proposition being a quantification over types, which I think is true.
Now I want to point out several reasons to avoidProp and impredicativity based on Prop. Note that I'm not asking you to get rid of impredicativity in general!
There is another related PASE question regarding termination. You don't have to read it, I'll paraphrase the example.
Usually, for structural induction, we have the notion of "comparing term size". For instance, if we have a pattern suc n, then recursively call the function itself with n on the same position is considered good, because we think n < suc n. But consider the following example.
left :: BrouwerTree -> Bool
+left (Leaf b) = b
+left (Branch xs) = left (xs 0)
Note that in the clause of left (Branch xs), the recursive call left (xs 0) is considered smaller, in other words, we think xs 0 < Branch xs.
This assumption is called 'predicative assumption'. As you may tell from the name, it can only be made on things that are predicative, and we know Prop is usually impredicative, so we should not allow this. At this point, you might expect a proof of false using predicative assumption on Prop, which I'll show in this blog post.
Note that allowing such recursion pattern is very important! The famous W-type is also using this assumption.
A counterexample with Prop looks like this (since we need to talk about universes and dependent types, we start using Agda syntax instead of Haskell):
data Bad : Prop where
+ branch : ((P : Prop) → P → P) → Bad
+
+bad : Bad
+bad = branch (λ P p → p)
+
+no-bad : Bad → ⊥
+no-bad (branch x) = no-bad (x Bad bad)
+
+very-bad : ⊥
+very-bad = no-bad bad
Notice that the no-bad (branch x) clause uses the recursion no-bad (x Bad bad), which is only valid with the predicative assumption. So, having this predicative assumption actually proves false for Prop, so for Prop, we need to patch the termination checker to ban this rule. So, how hard is it to patch the termination checker?
Coq and Lean have a similar problem, but they are generating eliminators for inductive definitions, so they can generate the correct eliminator for Prop, instead of patching the termination checker. Then, Coq carefully implements a comparison function for size-decreasing arguments (this means eliminators are not the "most primitive" thing in Coq, but the termination checker is also part of it. I got this piece of information from Lysxia and Meven Lennon-Bertrand). In Coq, the eliminator for Bad is
Bad_ind : forall P : Prop,
+ ((forall p : Prop, p -> p) -> P) ->
+ Bad -> P
Note that there is no recursive arguments, so there is no recursion allowed.
Now, this sounds like just adding some if statements to the termination checker, but the situation is actually worse. In Agda, metavariables are pervasive, like the following code is partially accepted:
data Bad : Prop where
+ b : ((P : { }0) → P → P) → Bad
Agda will not fail on this code, but then what to do in the termination checker is really unclear. If you're using a termination checker, you want to get rid of impredicativity of Prop! This eliminates the need of a universe-based irrelevance.
We may use axioms to get impredicativity. Suppose we define (since we no longer have it in the language) Prop := Σ (A : Type) (isProp A), there are two different axioms that imply impredicativity of Prop:
Propositional resizing, which is basically a restatement of impredicativity.
Classical axioms, which implies that A : Prop is either ⊤ or ⊥, which further implies that Prop ≅ Bool, which implies resizing.
A completely separate layer in the type theory that only concerns logic and propositions. This is similar to the solution in Russell's original simple theory of types, where we replace the "simple type" with dependent types.
If we think of the right way of doing math is to work with classical axioms, why on earth are we forging a weaker theorem as part of the language?
`,28)]))}const u=a(n,[["render",o]]);export{k as __pageData,u as default};
diff --git a/assets/blog_ind-prop.md.BgOiB5U1.lean.js b/assets/blog_ind-prop.md.BgOiB5U1.lean.js
new file mode 100644
index 0000000..f36903a
--- /dev/null
+++ b/assets/blog_ind-prop.md.BgOiB5U1.lean.js
@@ -0,0 +1,18 @@
+import{_ as a,c as i,a2 as s,o as t}from"./chunks/framework.BnE-uSbk.js";const k=JSON.parse('{"title":"Impredicative Props are hard","description":"","frontmatter":{},"headers":[],"relativePath":"blog/ind-prop.md","filePath":"blog/ind-prop.md","lastUpdated":1718905368000}'),n={name:"blog/ind-prop.md"};function o(p,e,r,l,h,d){return t(),i("div",null,e[0]||(e[0]=[s(`
Throughout this blog post, I will use the term Prop to mean the type of propositions, which does not have to be strict, but has the property that it cannot eliminate to Type.
Long time ago I wrote a PASE question regarding definitional irrelevance. An important pro of Prop in my opinion is that it is more convenient to be turned impredicative. Mathematicians want impredicativity for various reasons, one thing being that it is natural to have a proposition being a quantification over types, which I think is true.
Now I want to point out several reasons to avoidProp and impredicativity based on Prop. Note that I'm not asking you to get rid of impredicativity in general!
There is another related PASE question regarding termination. You don't have to read it, I'll paraphrase the example.
Usually, for structural induction, we have the notion of "comparing term size". For instance, if we have a pattern suc n, then recursively call the function itself with n on the same position is considered good, because we think n < suc n. But consider the following example.
left :: BrouwerTree -> Bool
+left (Leaf b) = b
+left (Branch xs) = left (xs 0)
Note that in the clause of left (Branch xs), the recursive call left (xs 0) is considered smaller, in other words, we think xs 0 < Branch xs.
This assumption is called 'predicative assumption'. As you may tell from the name, it can only be made on things that are predicative, and we know Prop is usually impredicative, so we should not allow this. At this point, you might expect a proof of false using predicative assumption on Prop, which I'll show in this blog post.
Note that allowing such recursion pattern is very important! The famous W-type is also using this assumption.
A counterexample with Prop looks like this (since we need to talk about universes and dependent types, we start using Agda syntax instead of Haskell):
data Bad : Prop where
+ branch : ((P : Prop) → P → P) → Bad
+
+bad : Bad
+bad = branch (λ P p → p)
+
+no-bad : Bad → ⊥
+no-bad (branch x) = no-bad (x Bad bad)
+
+very-bad : ⊥
+very-bad = no-bad bad
Notice that the no-bad (branch x) clause uses the recursion no-bad (x Bad bad), which is only valid with the predicative assumption. So, having this predicative assumption actually proves false for Prop, so for Prop, we need to patch the termination checker to ban this rule. So, how hard is it to patch the termination checker?
Coq and Lean have a similar problem, but they are generating eliminators for inductive definitions, so they can generate the correct eliminator for Prop, instead of patching the termination checker. Then, Coq carefully implements a comparison function for size-decreasing arguments (this means eliminators are not the "most primitive" thing in Coq, but the termination checker is also part of it. I got this piece of information from Lysxia and Meven Lennon-Bertrand). In Coq, the eliminator for Bad is
Bad_ind : forall P : Prop,
+ ((forall p : Prop, p -> p) -> P) ->
+ Bad -> P
Note that there is no recursive arguments, so there is no recursion allowed.
Now, this sounds like just adding some if statements to the termination checker, but the situation is actually worse. In Agda, metavariables are pervasive, like the following code is partially accepted:
data Bad : Prop where
+ b : ((P : { }0) → P → P) → Bad
Agda will not fail on this code, but then what to do in the termination checker is really unclear. If you're using a termination checker, you want to get rid of impredicativity of Prop! This eliminates the need of a universe-based irrelevance.
We may use axioms to get impredicativity. Suppose we define (since we no longer have it in the language) Prop := Σ (A : Type) (isProp A), there are two different axioms that imply impredicativity of Prop:
Propositional resizing, which is basically a restatement of impredicativity.
Classical axioms, which implies that A : Prop is either ⊤ or ⊥, which further implies that Prop ≅ Bool, which implies resizing.
A completely separate layer in the type theory that only concerns logic and propositions. This is similar to the solution in Russell's original simple theory of types, where we replace the "simple type" with dependent types.
If we think of the right way of doing math is to work with classical axioms, why on earth are we forging a weaker theorem as part of the language?
`,28)]))}const u=a(n,[["render",o]]);export{k as __pageData,u as default};
diff --git a/assets/blog_index-unification.md.DR8rUZJu.js b/assets/blog_index-unification.md.DR8rUZJu.js
new file mode 100644
index 0000000..aa0af3c
--- /dev/null
+++ b/assets/blog_index-unification.md.DR8rUZJu.js
@@ -0,0 +1,7 @@
+import{_ as t,c as a,a2 as n,o}from"./chunks/framework.BnE-uSbk.js";const u=JSON.parse('{"title":"Index unification and forced patterns in Aya","description":"","frontmatter":{},"headers":[],"relativePath":"blog/index-unification.md","filePath":"blog/index-unification.md","lastUpdated":1661920240000}'),i={name:"blog/index-unification.md"};function s(c,e,d,r,l,p){return o(),a("div",null,e[0]||(e[0]=[n(`
Aya implements a version of index unification algorithm that allows emission of obvious patterns. Here's an example. Consider the famous "sized-vector" Vec (n : Nat) (A : Type) definition, and we can perform some pattern matching:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len a vnil = 0
+len a (vcons _ x) = suc (len _ x)
This code may seem obviously correct, but why would I write about it if it's so simple? 😉 Let's run the type checking in our head, clause by clause and pattern by pattern.
The first pattern in the first clause, a, is a valid pattern for Nat. This means we will substitute the codomain of the pattern matching with [a/n], where n is the corresponding name in the telescope and a is the term corresponding to the pattern.
The second pattern in the first clause, vnil, is a pattern for Vec zero A. However, the expected type is Vec a A, which does not match the type of the pattern.
So, here is the problem! The well-typed version of the program is actually:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len zero vnil = 0
+len (suc a) (vcons _ x) = suc (len a x)
However, isn't it obvious that the first pattern in the first clause must be zero? It would be nice if the type checker can figure this out by itself. In fact, both Agda and Idris can do this! In Agda, the feature is called "dotted patterns" in the documentation and "inaccessible patterns" in the paper. I will prefer calling it "forced patterns" because the patterns are actually accessible (in the sense that the bindings in the patterns are used) and does not use the Agda dot syntax.
Forced patterns are not easy to implement. The simplest pattern type checking algorithm can be quite straightforward: we check the type of the pattern, add the bindings to the context so we can type the rest of the telescope, and check the body of the clause. With forced patterns, we will need to change the existing well-typed variable patterns into constructor patterns, so the algorithm becomes stateful.
In Aya, I introduced the concept of "meta patteriables" which is a funny reference to "meta variables" used in unification in conversion check.
When we see a variable pattern, we transform it into a MetaPat which is a "unification variable" pattern that can be "solved" into another pattern. A reference to a MetaPat is converted into a special meta variable that has a mutable reference to the MetaPat (this can be replaced by a mutable map in the type checking state when you need purity, but I prefer mutable references for implementation simplicity).
When we are type checking a pattern of type D a for D an indexed inductive family and the expected type is D b where b is the special meta variable, we claim that b is solved to a, and the MetaPat that corresponds to b will be transformed into a when we finalize the type checking results.
There are two more cases to deal with:
In case a MetaPat is not "solved", we just let it be a variable pattern.
In case a MetaPat is "solved" more than once, we must make sure the solutions are identical.
Note that a MetaPat may contain bindings, but these bindings are already from the current context, so we do not need to add them again to the context.
Now, let's run the new algorithm:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len a vnil = 0
+len a (vcons _ x) = suc (len _ x)
The first pattern in the first clause, a, is a valid pattern for Nat, so we generate a MetaPat(a) and substitute the codomain with MetaPatRef(a), e.g. Vec MetaPatRef(a) A -> Nat.
The second pattern in the first clause, vnil, is a pattern for Vec zero A. The expected type is Vec MetaPatRef(a) A, and we solve MetaPat(a) to zero.
Now we check the body and finalize the clause. Since a is solved to zero, we generate the well-typed clause len zero vnil = 0 which is exactly what we need.
Thanks for reading!
`,21)]))}const f=t(i,[["render",s]]);export{u as __pageData,f as default};
diff --git a/assets/blog_index-unification.md.DR8rUZJu.lean.js b/assets/blog_index-unification.md.DR8rUZJu.lean.js
new file mode 100644
index 0000000..aa0af3c
--- /dev/null
+++ b/assets/blog_index-unification.md.DR8rUZJu.lean.js
@@ -0,0 +1,7 @@
+import{_ as t,c as a,a2 as n,o}from"./chunks/framework.BnE-uSbk.js";const u=JSON.parse('{"title":"Index unification and forced patterns in Aya","description":"","frontmatter":{},"headers":[],"relativePath":"blog/index-unification.md","filePath":"blog/index-unification.md","lastUpdated":1661920240000}'),i={name:"blog/index-unification.md"};function s(c,e,d,r,l,p){return o(),a("div",null,e[0]||(e[0]=[n(`
Aya implements a version of index unification algorithm that allows emission of obvious patterns. Here's an example. Consider the famous "sized-vector" Vec (n : Nat) (A : Type) definition, and we can perform some pattern matching:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len a vnil = 0
+len a (vcons _ x) = suc (len _ x)
This code may seem obviously correct, but why would I write about it if it's so simple? 😉 Let's run the type checking in our head, clause by clause and pattern by pattern.
The first pattern in the first clause, a, is a valid pattern for Nat. This means we will substitute the codomain of the pattern matching with [a/n], where n is the corresponding name in the telescope and a is the term corresponding to the pattern.
The second pattern in the first clause, vnil, is a pattern for Vec zero A. However, the expected type is Vec a A, which does not match the type of the pattern.
So, here is the problem! The well-typed version of the program is actually:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len zero vnil = 0
+len (suc a) (vcons _ x) = suc (len a x)
However, isn't it obvious that the first pattern in the first clause must be zero? It would be nice if the type checker can figure this out by itself. In fact, both Agda and Idris can do this! In Agda, the feature is called "dotted patterns" in the documentation and "inaccessible patterns" in the paper. I will prefer calling it "forced patterns" because the patterns are actually accessible (in the sense that the bindings in the patterns are used) and does not use the Agda dot syntax.
Forced patterns are not easy to implement. The simplest pattern type checking algorithm can be quite straightforward: we check the type of the pattern, add the bindings to the context so we can type the rest of the telescope, and check the body of the clause. With forced patterns, we will need to change the existing well-typed variable patterns into constructor patterns, so the algorithm becomes stateful.
In Aya, I introduced the concept of "meta patteriables" which is a funny reference to "meta variables" used in unification in conversion check.
When we see a variable pattern, we transform it into a MetaPat which is a "unification variable" pattern that can be "solved" into another pattern. A reference to a MetaPat is converted into a special meta variable that has a mutable reference to the MetaPat (this can be replaced by a mutable map in the type checking state when you need purity, but I prefer mutable references for implementation simplicity).
When we are type checking a pattern of type D a for D an indexed inductive family and the expected type is D b where b is the special meta variable, we claim that b is solved to a, and the MetaPat that corresponds to b will be transformed into a when we finalize the type checking results.
There are two more cases to deal with:
In case a MetaPat is not "solved", we just let it be a variable pattern.
In case a MetaPat is "solved" more than once, we must make sure the solutions are identical.
Note that a MetaPat may contain bindings, but these bindings are already from the current context, so we do not need to add them again to the context.
Now, let's run the new algorithm:
len : ∀ {A} -> (n : Nat) -> Vec n A -> Nat
+len a vnil = 0
+len a (vcons _ x) = suc (len _ x)
The first pattern in the first clause, a, is a valid pattern for Nat, so we generate a MetaPat(a) and substitute the codomain with MetaPatRef(a), e.g. Vec MetaPatRef(a) A -> Nat.
The second pattern in the first clause, vnil, is a pattern for Vec zero A. The expected type is Vec MetaPatRef(a) A, and we solve MetaPat(a) to zero.
Now we check the body and finalize the clause. Since a is solved to zero, we generate the well-typed clause len zero vnil = 0 which is exactly what we need.
Thanks for reading!
`,21)]))}const f=t(i,[["render",s]]);export{u as __pageData,f as default};
diff --git a/assets/blog_index.md.DR7jCmfM.js b/assets/blog_index.md.DR7jCmfM.js
new file mode 100644
index 0000000..18a8b12
--- /dev/null
+++ b/assets/blog_index.md.DR7jCmfM.js
@@ -0,0 +1 @@
+import{_ as t,c as o,j as e,a as s,o as r}from"./chunks/framework.BnE-uSbk.js";const f=JSON.parse('{"title":"Aya blogs","description":"","frontmatter":{},"headers":[],"relativePath":"blog/index.md","filePath":"blog/index.md","lastUpdated":1662566075000}'),n={name:"blog/index.md"};function l(i,a,d,c,p,b){return r(),o("div",null,a[0]||(a[0]=[e("h1",{id:"aya-blogs",tabindex:"-1"},[s("Aya blogs "),e("a",{class:"header-anchor",href:"#aya-blogs","aria-label":'Permalink to "Aya blogs"'},"")],-1),e("p",null,"See the sidebar 👈 for the list of blog posts.",-1),e("p",null,"Note that some posts are written before some breaking syntax changes. The code examples may not work with the latest version of Aya.",-1)]))}const h=t(n,[["render",l]]);export{f as __pageData,h as default};
diff --git a/assets/blog_index.md.DR7jCmfM.lean.js b/assets/blog_index.md.DR7jCmfM.lean.js
new file mode 100644
index 0000000..18a8b12
--- /dev/null
+++ b/assets/blog_index.md.DR7jCmfM.lean.js
@@ -0,0 +1 @@
+import{_ as t,c as o,j as e,a as s,o as r}from"./chunks/framework.BnE-uSbk.js";const f=JSON.parse('{"title":"Aya blogs","description":"","frontmatter":{},"headers":[],"relativePath":"blog/index.md","filePath":"blog/index.md","lastUpdated":1662566075000}'),n={name:"blog/index.md"};function l(i,a,d,c,p,b){return r(),o("div",null,a[0]||(a[0]=[e("h1",{id:"aya-blogs",tabindex:"-1"},[s("Aya blogs "),e("a",{class:"header-anchor",href:"#aya-blogs","aria-label":'Permalink to "Aya blogs"'},"")],-1),e("p",null,"See the sidebar 👈 for the list of blog posts.",-1),e("p",null,"Note that some posts are written before some breaking syntax changes. The code examples may not work with the latest version of Aya.",-1)]))}const h=t(n,[["render",l]]);export{f as __pageData,h as default};
diff --git a/assets/blog_lang-exts.md.hyGXHWfR.js b/assets/blog_lang-exts.md.hyGXHWfR.js
new file mode 100644
index 0000000..7afd359
--- /dev/null
+++ b/assets/blog_lang-exts.md.hyGXHWfR.js
@@ -0,0 +1 @@
+import{_ as a,c as t,a2 as s,o as i}from"./chunks/framework.BnE-uSbk.js";const g=JSON.parse('{"title":"Haskell or Agda style extensions","description":"","frontmatter":{},"headers":[],"relativePath":"blog/lang-exts.md","filePath":"blog/lang-exts.md","lastUpdated":1662566075000}'),o={name:"blog/lang-exts.md"};function n(r,e,l,c,u,d){return i(),t("div",null,e[0]||(e[0]=[s('
In Haskell, you can do {-# LANGUAGE TypeFamilies #-}, and similarly in Agda you can {-# OPTIONS --two-levels #-}. These "pragma" can also be specified via command line arguments. Since Haskell is too weak and even basic features need extensions, I'll be avoiding talking about it and stick to Agda.
Disable or enable (particularly disable) certain checks or compiler phases such as positivity checks, termination checks, deletion rule in unification, etc.
Modify the compiler by changing some parameters, such as termination check's recursion depth, use call-by-name instead of call-by-need, cumulativity, etc.
Disable or enable (particularly enable) certain language features, such as cubical features, sized types, custom rewriting rules, etc.
One special pragma is to ensure that no known inconsistent flag or combination of flags is turned on -- --safe. Let's discuss it later.
The current status of Agda libraries, that having separate cubical, HoTT library, and standard library, implementing the basic features individually, is a significant evidence that Agda is barely a programming language, but a collection of programming languages that share a lot in common and have good interoperability. Each flag that enables a certain language feature makes Agda a different language, and it is difficult in general to make two different language source-to-source compatible (see Kotlin-Java, Scala-Java, etc).
It is good to keep your language evolving like Agda (adding new features aggressively), and indeed Agda is the proof assistant with the richest set of language features I've known so far. However, this also negatively impacts Agda's reputation to some extent, that people say it's an experiment in type theory. Well, maybe it's not a negative impact, but it prevents big customers (such as Mathematicians looking for a tool to formalize math) from choosing the language. At least, we don't want this to happen to our language.
So, we will not introduce any "feature" flags, and will have only one base library. Aya will be one language, its features are its features. If we decide on removing a feature, then we remove it from the language (not going to keep it as an optional flag). If we decide on adding a feature, we add it and it should be available without any options.
It should still be encouraged to add some fancy, experimental features, but I think they should stay in branches or forks and will be either enlisted to the language or abandoned eventually.
However, the "parameters" part is not as bad. For example, it is very easy to allow type-in-type in the type checker -- we just disable the level solver. This is useful when the level solver prevents us from experimenting something classical using our language features but unfortunately the level solver is just unhappy with something minor. We can also like tweak the conversion checking algorithm we use, like we can use a simpler one that only solves first-order equations or we can enable the full-blown pattern unification algorithm. Verbosity levels, can also be seen as such parameter, and it's extremely useful for debugging the compiler. So we can apply that.
To be honest, it's hard to decide on a semantic of the word "safe", and relate that to the Agda pragma --safe. To me, it means "logical consistency", and if we can set --safe as the last argument of an Agda file, it should be guaranteed by Agda that it cannot provide you a proof of false. There are many related discussion in the Agda issue tracker that talks 'bout how should --safe behave. Sometimes it fits my guess (for logical consistency), sometimes it implies more stuffs.
Anyway, a "logical consistency" flag seems useful, and will probably appear in Aya.
For disabling or enabling some checks, if we disable a check that is required to be consistent, then it should break --safe. I think we will of course enable all of these checks by default, so exploiting the disabledness of a check can lead to inconsistency eventually. So, we can use an "unsafe" flag to ensure that our language is only unsafe when we want it to be. It is quite meaningful as well to have an "unsafe" mode, from a real-world programming perspective.
We'll have a language, with some flags that tweaks the parameters of some algorithms (which are no-harm), and some flags for disabling some checks (which will lead to an error at the end of tycking), and an unsafe flag that enables a set of features such as sorry and suppresses the error of disabling checks.
Speaking of the base library design, I have some vague ideas in mind. I'd like it to be split into three parts (not sure if we're gonna make it three modules inside one stdlib or three standalone libraries):
The base part, for basic definitions like lists, trees, sorting, rings, categories, path lemmas, simple tactics like rewrites, etc.
The programming part, for I/O, effects, unsafe operations, FFI, etc.
The math part, like arend-lib or Lean's mathlib.
Then, we can use these libraries on-demand.
',22)]))}const f=a(o,[["render",n]]);export{g as __pageData,f as default};
diff --git a/assets/blog_lang-exts.md.hyGXHWfR.lean.js b/assets/blog_lang-exts.md.hyGXHWfR.lean.js
new file mode 100644
index 0000000..7afd359
--- /dev/null
+++ b/assets/blog_lang-exts.md.hyGXHWfR.lean.js
@@ -0,0 +1 @@
+import{_ as a,c as t,a2 as s,o as i}from"./chunks/framework.BnE-uSbk.js";const g=JSON.parse('{"title":"Haskell or Agda style extensions","description":"","frontmatter":{},"headers":[],"relativePath":"blog/lang-exts.md","filePath":"blog/lang-exts.md","lastUpdated":1662566075000}'),o={name:"blog/lang-exts.md"};function n(r,e,l,c,u,d){return i(),t("div",null,e[0]||(e[0]=[s('
In Haskell, you can do {-# LANGUAGE TypeFamilies #-}, and similarly in Agda you can {-# OPTIONS --two-levels #-}. These "pragma" can also be specified via command line arguments. Since Haskell is too weak and even basic features need extensions, I'll be avoiding talking about it and stick to Agda.
Disable or enable (particularly disable) certain checks or compiler phases such as positivity checks, termination checks, deletion rule in unification, etc.
Modify the compiler by changing some parameters, such as termination check's recursion depth, use call-by-name instead of call-by-need, cumulativity, etc.
Disable or enable (particularly enable) certain language features, such as cubical features, sized types, custom rewriting rules, etc.
One special pragma is to ensure that no known inconsistent flag or combination of flags is turned on -- --safe. Let's discuss it later.
The current status of Agda libraries, that having separate cubical, HoTT library, and standard library, implementing the basic features individually, is a significant evidence that Agda is barely a programming language, but a collection of programming languages that share a lot in common and have good interoperability. Each flag that enables a certain language feature makes Agda a different language, and it is difficult in general to make two different language source-to-source compatible (see Kotlin-Java, Scala-Java, etc).
It is good to keep your language evolving like Agda (adding new features aggressively), and indeed Agda is the proof assistant with the richest set of language features I've known so far. However, this also negatively impacts Agda's reputation to some extent, that people say it's an experiment in type theory. Well, maybe it's not a negative impact, but it prevents big customers (such as Mathematicians looking for a tool to formalize math) from choosing the language. At least, we don't want this to happen to our language.
So, we will not introduce any "feature" flags, and will have only one base library. Aya will be one language, its features are its features. If we decide on removing a feature, then we remove it from the language (not going to keep it as an optional flag). If we decide on adding a feature, we add it and it should be available without any options.
It should still be encouraged to add some fancy, experimental features, but I think they should stay in branches or forks and will be either enlisted to the language or abandoned eventually.
However, the "parameters" part is not as bad. For example, it is very easy to allow type-in-type in the type checker -- we just disable the level solver. This is useful when the level solver prevents us from experimenting something classical using our language features but unfortunately the level solver is just unhappy with something minor. We can also like tweak the conversion checking algorithm we use, like we can use a simpler one that only solves first-order equations or we can enable the full-blown pattern unification algorithm. Verbosity levels, can also be seen as such parameter, and it's extremely useful for debugging the compiler. So we can apply that.
To be honest, it's hard to decide on a semantic of the word "safe", and relate that to the Agda pragma --safe. To me, it means "logical consistency", and if we can set --safe as the last argument of an Agda file, it should be guaranteed by Agda that it cannot provide you a proof of false. There are many related discussion in the Agda issue tracker that talks 'bout how should --safe behave. Sometimes it fits my guess (for logical consistency), sometimes it implies more stuffs.
Anyway, a "logical consistency" flag seems useful, and will probably appear in Aya.
For disabling or enabling some checks, if we disable a check that is required to be consistent, then it should break --safe. I think we will of course enable all of these checks by default, so exploiting the disabledness of a check can lead to inconsistency eventually. So, we can use an "unsafe" flag to ensure that our language is only unsafe when we want it to be. It is quite meaningful as well to have an "unsafe" mode, from a real-world programming perspective.
We'll have a language, with some flags that tweaks the parameters of some algorithms (which are no-harm), and some flags for disabling some checks (which will lead to an error at the end of tycking), and an unsafe flag that enables a set of features such as sorry and suppresses the error of disabling checks.
Speaking of the base library design, I have some vague ideas in mind. I'd like it to be split into three parts (not sure if we're gonna make it three modules inside one stdlib or three standalone libraries):
The base part, for basic definitions like lists, trees, sorting, rings, categories, path lemmas, simple tactics like rewrites, etc.
The programming part, for I/O, effects, unsafe operations, FFI, etc.
The math part, like arend-lib or Lean's mathlib.
Then, we can use these libraries on-demand.
',22)]))}const f=a(o,[["render",n]]);export{g as __pageData,f as default};
diff --git a/assets/blog_path-elab.md.DXdo4WbU.js b/assets/blog_path-elab.md.DXdo4WbU.js
new file mode 100644
index 0000000..f225e7e
--- /dev/null
+++ b/assets/blog_path-elab.md.DXdo4WbU.js
@@ -0,0 +1,21 @@
+import{_ as a,c as t,a2 as n,o as s}from"./chunks/framework.BnE-uSbk.js";const u=JSON.parse('{"title":"Elaboration of the \\"extension\\" type","description":"","frontmatter":{},"headers":[],"relativePath":"blog/path-elab.md","filePath":"blog/path-elab.md","lastUpdated":1679673438000}'),i={name:"blog/path-elab.md"};function o(p,e,l,r,c,h){return s(),t("div",null,e[0]||(e[0]=[n(`
Aya uses the so-called "extension" type (probably first-appeared here) as a generalized version of path type.
Instead of using the conventional path type, as in Cubical Agda:
PathP (λ i → A i) a b for a : A 0 and b : A 1
λ i → a : PathP (λ i → A i) (a 0) (a 1) for a : A i
p i : A i for p : PathP (λ i → A i) a b
p 0 = a and p 1 = b
This type looks good, but it does not scale to higher dimensions. Consider, for example, the type of a square with four faces specified (from Agda's cubical library):
It gets even worse when the type is heterogeneous:
SquareP :
+ (A : I → I → Type ℓ)
+ {a₀₀ : A i0 i0} {a₀₁ : A i0 i1} (a₀₋ : PathP (λ j → A i0 j) a₀₀ a₀₁)
+ {a₁₀ : A i1 i0} {a₁₁ : A i1 i1} (a₁₋ : PathP (λ j → A i1 j) a₁₀ a₁₁)
+ (a₋₀ : PathP (λ i → A i i0) a₀₀ a₁₀) (a₋₁ : PathP (λ i → A i i1) a₀₁ a₁₁)
+ → Type ℓ
+SquareP A a₀₋ a₁₋ a₋₀ a₋₁ = PathP (λ i → PathP (λ j → A i j) (a₋₀ i) (a₋₁ i)) a₀₋ a₁₋
We have decided to use a partial element to represent these faces, and so we can freely add or delete these a face, without having to explicitly write down all faces for generality. This leads to the following syntax:
-------- ↓ type ↓ the "i = 0" end is b
+[| i |] (A i) {| i := a | ~ i := b |}
+-- ^ interval ^ the "i = 1" end is a
The above type is equivalent to PathP (λ i → A i) a b. We may use this to simplify the type signature of path concatenation:
def concat {A : Type}
+ (p : [| i |] A {| |})
+ (q : [| i |] A {| ~ i := p 1 |})
+ : [| i |] A {| ~ i := p 0 | i := q 1 |}
It has fewer parameters than the conventional version:
def concat {A : Type}
+ {a b c : A}
+ (p : Path A a b)
+ (q : Path A b c)
+ : Path A a c
Now, how to implement this type? We have decided to overload lambdas and expressions as Cubical Agda did, but we have encountered several problems. Here's the story, in chronological order.
Below, we use "type checking" and we actually mean "elaboration".
Principle: do not annotate the terms (including variable references) with types, because this is going to harm efficiency and the code that tries to generate terms (now they'll have to generate the types as well, pain!).
Problem: reduction of path application is type-directed, like p 1 will reduce according to the type of p.
Solution: annotate the path applications instead. Every time we do type checking & we get a term of path type, we "η-expand" it into a normal lambda expression with a path application inside. This secures the reduction of path applications.
New Problem: we expand too much. In case we want to check the type of term against a path type, the term is actually η-expanded and has a Π-type. So, we have the manually write path lambdas everywhere, e.g. given p : Path A a b, and only λ i → p i is a valid term of type Path A a b, not p (which is internally a lambda).
Lesson: we need to preserve the types somehow, generate path applications only when necessary.
New Solution: when checking something against a path type, we directly apply the boundary checks, instead of trying to invoke synthesize and unify the types. This eliminates a lot of λ i → p i problems.
New Problem: this is incompatible with implicit arguments. Consider the following problem:
have: idp : {a : A} -> Path A a a
elaborated: λ i → idp i : {a : A} -> I -> A
check: idp : Path Nat zero zero
The new solution will try to apply the boundary before inserting the implicit arguments, which leads to type-incorrect terms.
Lesson: we probably should not change the bidirectional type checking algorithm too much.
New Solution: the type information is known in the bidirectional type checking anyway, so we only generate path applications during the type checking of application terms.
This has worked so far, with some unsolved problems (yet to be discussed):
Is p : [| i |] A {| |} an instance of type [| i |] A {| i := a |}?
Currently, Aya do not think so.
Can we automatically turn Agda-style squares to its preferred version in generalized path type?
The implementation has been updated to solve some the above problems partially. Essentially, we need to do one thing: coercive subtyping. Since the type checking already respects the type (say, does not change the type), it remains to insert an η-expansion when the subtyping is invoked. We also need to store the boundary information in the path application term to have simple normalization algorithm.
Carlo Angiuli told me that in cooltt, the path type is decoded (in the sense of the universe à la Tarski el operator) into a Π-type that returns a cubical subtype, and since el is not required to be injective, this should be fine. At first, I was worried about the fibrancy of the path type, because a Π-type into a subtype is not fibrant, but it turns out that this is unrelated. We don't talk about the fibrancy of the types, but only the fibrancy of the type codes.
`,36)]))}const b=a(i,[["render",o]]);export{u as __pageData,b as default};
diff --git a/assets/blog_path-elab.md.DXdo4WbU.lean.js b/assets/blog_path-elab.md.DXdo4WbU.lean.js
new file mode 100644
index 0000000..f225e7e
--- /dev/null
+++ b/assets/blog_path-elab.md.DXdo4WbU.lean.js
@@ -0,0 +1,21 @@
+import{_ as a,c as t,a2 as n,o as s}from"./chunks/framework.BnE-uSbk.js";const u=JSON.parse('{"title":"Elaboration of the \\"extension\\" type","description":"","frontmatter":{},"headers":[],"relativePath":"blog/path-elab.md","filePath":"blog/path-elab.md","lastUpdated":1679673438000}'),i={name:"blog/path-elab.md"};function o(p,e,l,r,c,h){return s(),t("div",null,e[0]||(e[0]=[n(`
Aya uses the so-called "extension" type (probably first-appeared here) as a generalized version of path type.
Instead of using the conventional path type, as in Cubical Agda:
PathP (λ i → A i) a b for a : A 0 and b : A 1
λ i → a : PathP (λ i → A i) (a 0) (a 1) for a : A i
p i : A i for p : PathP (λ i → A i) a b
p 0 = a and p 1 = b
This type looks good, but it does not scale to higher dimensions. Consider, for example, the type of a square with four faces specified (from Agda's cubical library):
It gets even worse when the type is heterogeneous:
SquareP :
+ (A : I → I → Type ℓ)
+ {a₀₀ : A i0 i0} {a₀₁ : A i0 i1} (a₀₋ : PathP (λ j → A i0 j) a₀₀ a₀₁)
+ {a₁₀ : A i1 i0} {a₁₁ : A i1 i1} (a₁₋ : PathP (λ j → A i1 j) a₁₀ a₁₁)
+ (a₋₀ : PathP (λ i → A i i0) a₀₀ a₁₀) (a₋₁ : PathP (λ i → A i i1) a₀₁ a₁₁)
+ → Type ℓ
+SquareP A a₀₋ a₁₋ a₋₀ a₋₁ = PathP (λ i → PathP (λ j → A i j) (a₋₀ i) (a₋₁ i)) a₀₋ a₁₋
We have decided to use a partial element to represent these faces, and so we can freely add or delete these a face, without having to explicitly write down all faces for generality. This leads to the following syntax:
-------- ↓ type ↓ the "i = 0" end is b
+[| i |] (A i) {| i := a | ~ i := b |}
+-- ^ interval ^ the "i = 1" end is a
The above type is equivalent to PathP (λ i → A i) a b. We may use this to simplify the type signature of path concatenation:
def concat {A : Type}
+ (p : [| i |] A {| |})
+ (q : [| i |] A {| ~ i := p 1 |})
+ : [| i |] A {| ~ i := p 0 | i := q 1 |}
It has fewer parameters than the conventional version:
def concat {A : Type}
+ {a b c : A}
+ (p : Path A a b)
+ (q : Path A b c)
+ : Path A a c
Now, how to implement this type? We have decided to overload lambdas and expressions as Cubical Agda did, but we have encountered several problems. Here's the story, in chronological order.
Below, we use "type checking" and we actually mean "elaboration".
Principle: do not annotate the terms (including variable references) with types, because this is going to harm efficiency and the code that tries to generate terms (now they'll have to generate the types as well, pain!).
Problem: reduction of path application is type-directed, like p 1 will reduce according to the type of p.
Solution: annotate the path applications instead. Every time we do type checking & we get a term of path type, we "η-expand" it into a normal lambda expression with a path application inside. This secures the reduction of path applications.
New Problem: we expand too much. In case we want to check the type of term against a path type, the term is actually η-expanded and has a Π-type. So, we have the manually write path lambdas everywhere, e.g. given p : Path A a b, and only λ i → p i is a valid term of type Path A a b, not p (which is internally a lambda).
Lesson: we need to preserve the types somehow, generate path applications only when necessary.
New Solution: when checking something against a path type, we directly apply the boundary checks, instead of trying to invoke synthesize and unify the types. This eliminates a lot of λ i → p i problems.
New Problem: this is incompatible with implicit arguments. Consider the following problem:
have: idp : {a : A} -> Path A a a
elaborated: λ i → idp i : {a : A} -> I -> A
check: idp : Path Nat zero zero
The new solution will try to apply the boundary before inserting the implicit arguments, which leads to type-incorrect terms.
Lesson: we probably should not change the bidirectional type checking algorithm too much.
New Solution: the type information is known in the bidirectional type checking anyway, so we only generate path applications during the type checking of application terms.
This has worked so far, with some unsolved problems (yet to be discussed):
Is p : [| i |] A {| |} an instance of type [| i |] A {| i := a |}?
Currently, Aya do not think so.
Can we automatically turn Agda-style squares to its preferred version in generalized path type?
The implementation has been updated to solve some the above problems partially. Essentially, we need to do one thing: coercive subtyping. Since the type checking already respects the type (say, does not change the type), it remains to insert an η-expansion when the subtyping is invoked. We also need to store the boundary information in the path application term to have simple normalization algorithm.
Carlo Angiuli told me that in cooltt, the path type is decoded (in the sense of the universe à la Tarski el operator) into a Π-type that returns a cubical subtype, and since el is not required to be injective, this should be fine. At first, I was worried about the fibrancy of the path type, because a Π-type into a subtype is not fibrant, but it turns out that this is unrelated. We don't talk about the fibrancy of the types, but only the fibrancy of the type codes.
`,36)]))}const b=a(i,[["render",o]]);export{u as __pageData,b as default};
diff --git a/assets/blog_pathcon-elab.md.CriMvQIQ.js b/assets/blog_pathcon-elab.md.CriMvQIQ.js
new file mode 100644
index 0000000..fe7fc58
--- /dev/null
+++ b/assets/blog_pathcon-elab.md.CriMvQIQ.js
@@ -0,0 +1,10 @@
+import{_ as t,c as m,a2 as a,j as s,a as l,o as e}from"./chunks/framework.BnE-uSbk.js";const d=JSON.parse('{"title":"Elaboration of path constructors","description":"","frontmatter":{},"headers":[],"relativePath":"blog/pathcon-elab.md","filePath":"blog/pathcon-elab.md","lastUpdated":1717138752000}'),p={name:"blog/pathcon-elab.md"};function r(c,n,i,o,h,g){return e(),m("div",null,n[0]||(n[0]=[a('
So for example, set truncation from HoTT looks like this:
inductive SetTrunc (A : Type)
+| mk : A -> SetTrunc A
+| trunc : isSet (SetTrunc A)
The trunc constructor is elaborated to cubical syntax by flattening the type and attach the partial on the return type to the constructor, something like this:
trunc : Π (a b : SetTrunc A)
+ -> (p q : a = b)
+ -> (j i : I) -> SetTrunc A
+ { i = 1 -> a
+ ; i = 0 -> b
+ ; j = 1 -> q @ i
+ ; j = 0 -> p @ i
+ }
Aya is currently working on the so-called IApplyConfluence problem for recursive higher inductive types like SetTrunc, see this question which is a problem I'm wrapping my head around at the moment. More details will be posted later.
`,5)]))}const u=t(p,[["render",r]]);export{d as __pageData,u as default};
diff --git a/assets/blog_pathcon-elab.md.CriMvQIQ.lean.js b/assets/blog_pathcon-elab.md.CriMvQIQ.lean.js
new file mode 100644
index 0000000..fe7fc58
--- /dev/null
+++ b/assets/blog_pathcon-elab.md.CriMvQIQ.lean.js
@@ -0,0 +1,10 @@
+import{_ as t,c as m,a2 as a,j as s,a as l,o as e}from"./chunks/framework.BnE-uSbk.js";const d=JSON.parse('{"title":"Elaboration of path constructors","description":"","frontmatter":{},"headers":[],"relativePath":"blog/pathcon-elab.md","filePath":"blog/pathcon-elab.md","lastUpdated":1717138752000}'),p={name:"blog/pathcon-elab.md"};function r(c,n,i,o,h,g){return e(),m("div",null,n[0]||(n[0]=[a('
So for example, set truncation from HoTT looks like this:
inductive SetTrunc (A : Type)
+| mk : A -> SetTrunc A
+| trunc : isSet (SetTrunc A)
The trunc constructor is elaborated to cubical syntax by flattening the type and attach the partial on the return type to the constructor, something like this:
trunc : Π (a b : SetTrunc A)
+ -> (p q : a = b)
+ -> (j i : I) -> SetTrunc A
+ { i = 1 -> a
+ ; i = 0 -> b
+ ; j = 1 -> q @ i
+ ; j = 0 -> p @ i
+ }
Aya is currently working on the so-called IApplyConfluence problem for recursive higher inductive types like SetTrunc, see this question which is a problem I'm wrapping my head around at the moment. More details will be posted later.
`,5)]))}const u=t(p,[["render",r]]);export{d as __pageData,u as default};
diff --git a/assets/blog_redirect.md.Ch6PGAGu.js b/assets/blog_redirect.md.Ch6PGAGu.js
new file mode 100644
index 0000000..40ae0ef
--- /dev/null
+++ b/assets/blog_redirect.md.Ch6PGAGu.js
@@ -0,0 +1 @@
+import{_ as a,c as o,j as e,a as r,o as s}from"./chunks/framework.BnE-uSbk.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"blog/redirect.md","filePath":"blog/redirect.md","lastUpdated":1627270192000}'),n={name:"blog/redirect.md"};function l(d,t,p,c,i,m){return s(),o("div",null,t[0]||(t[0]=[e("p",null,"Hi OSSRH managers,",-1),e("p",null,[r("I'm Tesla Zhang and I own this aya-prover.org domain. I claim that it's me who created "),e("a",{href:"https://issues.sonatype.org/browse/OSSRH-71525",target:"_blank",rel:"noreferrer"},"OSSRH-71525"),r(". It's for the project "),e("a",{href:"https://github.com/aya-prover/aya-dev",target:"_blank",rel:"noreferrer"},"aya-prover"),r(".")],-1),e("p",null,"Thank you!",-1)]))}const g=a(n,[["render",l]]);export{h as __pageData,g as default};
diff --git a/assets/blog_redirect.md.Ch6PGAGu.lean.js b/assets/blog_redirect.md.Ch6PGAGu.lean.js
new file mode 100644
index 0000000..40ae0ef
--- /dev/null
+++ b/assets/blog_redirect.md.Ch6PGAGu.lean.js
@@ -0,0 +1 @@
+import{_ as a,c as o,j as e,a as r,o as s}from"./chunks/framework.BnE-uSbk.js";const h=JSON.parse('{"title":"","description":"","frontmatter":{},"headers":[],"relativePath":"blog/redirect.md","filePath":"blog/redirect.md","lastUpdated":1627270192000}'),n={name:"blog/redirect.md"};function l(d,t,p,c,i,m){return s(),o("div",null,t[0]||(t[0]=[e("p",null,"Hi OSSRH managers,",-1),e("p",null,[r("I'm Tesla Zhang and I own this aya-prover.org domain. I claim that it's me who created "),e("a",{href:"https://issues.sonatype.org/browse/OSSRH-71525",target:"_blank",rel:"noreferrer"},"OSSRH-71525"),r(". It's for the project "),e("a",{href:"https://github.com/aya-prover/aya-dev",target:"_blank",rel:"noreferrer"},"aya-prover"),r(".")],-1),e("p",null,"Thank you!",-1)]))}const g=a(n,[["render",l]]);export{h as __pageData,g as default};
diff --git a/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.js b/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.js
new file mode 100644
index 0000000..12515bc
--- /dev/null
+++ b/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.js
@@ -0,0 +1,67 @@
+import{_ as V,c as A,a2 as i,j as a,a as s,o as g}from"./chunks/framework.BnE-uSbk.js";const w={mounted(){const p=new Map;function v(l){const e=l.querySelectorAll("a[href]");for(const r of e){const n=r.href,y=p.get(n)??new Set;y.add(r),p.set(n,y)}for(const r of e)r.onmouseover=function(){for(const n of p.get(this.href))n.classList.add("hover-highlight")},r.onmouseout=function(){for(const n of p.get(this.href))n.classList.remove("hover-highlight")}}function x(l){return decodeURIComponent(atob(l).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const f=(l=>{const e={};return(...r)=>{const n=JSON.stringify(r);return e[n]=e[n]||l(...r)}})(x);class d{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(r=>r!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let r=this.list.find(n=>n.userCreatedFrom===e);this.dismissIfNotUsed(r)}createHoverFor(e,r,n){let y=this.list.find(o=>o.userCreatedFrom===e);if(y&&y.userClicked)return y;let M=[];const C=this.list.filter(o=>{if(this.allowAutoDismissal(o))return M.push(o),!1;const c=o.userCreatedFrom,m=e;let h=m;for(;h;){if(h===c)return!0;h=h.parentElement}for(h=c;h;){if(h===m)return!0;h=h.parentElement}return!1});M.forEach(o=>this.dismiss(o));let t=document.createElement("div");t.userCreatedFrom=e,t.innerHTML="×"+f(r),t.classList.add("AyaTooltipPopup"),v(t);let b=this;if(t.handleEvent=function(o){if(o.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let c=this.children[0];if(!c)return;let m=this;c.style.visibility="visible",c.addEventListener("click",h=>b.dismiss(m))}o.type==="mouseover"&&(this.userIsThinking=!0),o.type==="mouseout"&&(this.userIsThinking=!1,b.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),n.appendChild(t),t.style.left=`${e.offsetLeft}px`,C.length===0){const o=e.getBoundingClientRect(),c=t.getBoundingClientRect();o.bottom+c.height+30>window.innerHeight?t.style.top=`calc(${e.offsetTop-c.height+8}px - 3em)`:t.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const o=Math.max(...C.map(c=>c.offsetTop+c.offsetHeight));t.style.top=`${o+8}px`}return this.list.push(t),t}}let T=new d;function u(l){return function(){let e=this;const r=e.getAttribute("data-tooltip-text");r&&(l?T.createHoverFor(e,r,document.body):T.fireAutoDismissalFor(e))}}v(document);{let l=document.getElementsByClassName("aya-tooltip");for(let e=0;eType Theory in Type Theory using Quotient Inductive Types
',2),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Tm",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(" ("),a("a",{id:"v1345483087",class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Con"},[a("span",{class:"Data"},"Con")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Ty"},[a("span",{class:"Data"},"Ty")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(") : "),a("span",{class:"Keyword"},"Type"),s(`
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(),a("a",{id:"v105579928",class:"aya-hover","aya-hover-text":"Ty _",href:"#v105579928"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{id:"v418958713",class:"aya-hover","aya-hover-text":"Ty (_ ▷ A)",href:"#v418958713"},[a("span",{class:"LocalVar"},"B")]),s(" ⇒ "),a("a",{id:"Mian-Tm-λ",class:"aya-hover","aya-hover-text":"Tm _ (Π A B)",href:"#Mian-Tm-λ"},[a("span",{class:"Constructor"},"λ")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#v105579928"},[a("span",{class:"LocalVar"},"A")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Ty (_ ▷ A)",href:"#v418958713"},[a("span",{class:"LocalVar"},"B")]),s(`)
+| `),a("a",{id:"v238762799",class:"aya-hover","aya-hover-text":"Con",href:"#v238762799"},[a("span",{class:"LocalVar"},"Γ'")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(),a("a",{id:"v1358343316",class:"aya-hover","aya-hover-text":"Ty Γ'",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(", "),a("a",{id:"v1824837049",class:"aya-hover","aya-hover-text":"Ty (Γ' ▷ A)",href:"#v1824837049"},[a("span",{class:"LocalVar"},"B")]),s(" ⇒ "),a("a",{id:"Mian-Tm-app",class:"aya-hover","aya-hover-text":"Tm (Γ' ▷ A) B",href:"#Mian-Tm-app"},[a("span",{class:"Constructor"},"app")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v238762799"},[a("span",{class:"LocalVar"},"Γ'")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ'",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ'",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty (Γ' ▷ A)",href:"#v1824837049"},[a("span",{class:"LocalVar"},"B")]),s(`))
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{id:"v685558284",class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v685558284"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{id:"v1171802656",class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v1171802656"},[a("span",{class:"LocalVar"},"δ")]),s(" ⇒ "),a("a",{id:"Mian-Tm-sub",class:"aya-hover","aya-hover-text":"Tm _ (Subst A δ)",href:"#Mian-Tm-sub"},[a("span",{class:"Constructor"},"sub")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3YxNTE1ODMzOTUwIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPs6UPC9zcGFuPjwvYT48L2NvZGU+CjwvcHJlPgo="},"_"),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v685558284"},[a("span",{class:"LocalVar"},"A")]),s(`)
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{id:"v859654796",class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v859654796"},[a("span",{class:"LocalVar"},"A")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Γ << Δ",href:"#Mian-3c3c-π₁"},[a("span",{class:"Constructor"},"π₁")]),s(),a("a",{id:"v1440621772",class:"aya-hover","aya-hover-text":"_ << (Δ ▷ B)",href:"#v1440621772"},[a("span",{class:"LocalVar"},"δ")]),s(") ⇒ "),a("a",{id:"Mian-Tm-π₂",class:"aya-hover","aya-hover-text":"Tm _ (Subst A (π₁ δ))",href:"#Mian-Tm-π₂"},[a("span",{class:"Constructor"},"π₂")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3c3c"},[a("span",{class:"Data"},"<<")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3Y4MjE1NzYzOTQiPjxzcGFuIGNsYXNzPSJMb2NhbFZhciI+zpQ8L3NwYW4+PC9hPjwvY29kZT4KPC9wcmU+Cg=="},"_"),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v859654796"},[a("span",{class:"LocalVar"},"A")]),s(`)
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{id:"v442199874",class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v442199874"},[a("span",{class:"LocalVar"},"B")]),s(),a("a",{id:"v1345900725",class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v1345900725"},[a("span",{class:"LocalVar"},"δ")]),s(),a("span",{class:"Keyword"},"as"),s(),a("a",{id:"v839998248",class:"aya-hover","aya-hover-text":"Ty _",href:"#v839998248"},[a("span",{class:"LocalVar"},"A")]),s(" ⇒ "),a("a",{id:"Mian-Tm-π₂β",class:"aya-hover","aya-hover-text":"coe 0 1 (\\ p0 ⇒ Tm _ (Subst B (π₁β t p0))) (π₂ (δ ∷ t)) = t",href:"#Mian-Tm-π₂β"},[a("span",{class:"Constructor"},"π₂β")]),s(" {"),a("a",{id:"v2107577743",class:"aya-hover","aya-hover-text":"Con",href:"#v2107577743"},[a("span",{class:"LocalVar"},"Δ")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Con"},[a("span",{class:"Data"},"Con")]),s("} ("),a("a",{id:"v1173346575",class:"aya-hover","aya-hover-text":"Tm _ (Subst B δ)",href:"#v1173346575"},[a("span",{class:"LocalVar"},"t")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#v839998248"},[a("span",{class:"LocalVar"},"A")]),s(`)
+ : `),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst B δ)",href:"#Mian-transport"},[a("span",{class:"Fn"},"transport")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Ty _ → Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3Y3MTg1NzEwOTEiPjxzcGFuIGNsYXNzPSJMb2NhbFZhciI+Xzwvc3Bhbj48L2E+PC9jb2RlPgo8L3ByZT4K"},"_"),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Subst B (π₁ (δ ∷ t)) = Subst B δ",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"(_ << Δ) → Ty _",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v442199874"},[a("span",{class:"LocalVar"},"B")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"I → _ << Δ",href:"#Mian-3c3c-π₁β"},[a("span",{class:"Constructor"},"π₁β")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst B δ)",href:"#v1173346575"},[a("span",{class:"LocalVar"},"t")]),s(")) ("),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst B (π₁ (δ ∷ t)))",href:"#Mian-Tm-π₂"},[a("span",{class:"Constructor"},"π₂")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v1345900725"},[a("span",{class:"LocalVar"},"δ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"?_ B δ _ Δ Δ t << (?Δ' B δ _ Δ Δ t ▷ ?A B δ _ Δ Δ t)",href:"#Mian-3c3c-∷"},[a("span",{class:"Constructor"},"∷")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst B δ)",href:"#v1173346575"},[a("span",{class:"LocalVar"},"t")]),s(")) "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst B δ)",href:"#v1173346575"},[a("span",{class:"LocalVar"},"t")]),s(`
+| _ `),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(" _, "),a("a",{id:"v405896924",class:"aya-hover","aya-hover-text":"Ty (_ ▷ _)",href:"#v405896924"},[a("span",{class:"LocalVar"},"A")]),s(" ⇒ "),a("a",{id:"Mian-Tm-Πβ",class:"aya-hover","aya-hover-text":"app (λ f) = f",href:"#Mian-Tm-Πβ"},[a("span",{class:"Constructor"},"Πβ")]),s(" ("),a("a",{id:"v1267105885",class:"aya-hover","aya-hover-text":"Tm (_ ▷ _) A",href:"#v1267105885"},[a("span",{class:"LocalVar"},"f")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty (_ ▷ _)",href:"#v405896924"},[a("span",{class:"LocalVar"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Tm (_ ▷ _) A",href:"#Mian-Tm-app"},[a("span",{class:"Constructor"},"app")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π _ A)",href:"#Mian-Tm-λ"},[a("span",{class:"Constructor"},"λ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm (_ ▷ _) A",href:"#v1267105885"},[a("span",{class:"LocalVar"},"f")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm (_ ▷ _) A",href:"#v1267105885"},[a("span",{class:"LocalVar"},"f")]),s(`
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(" _ _ "),a("span",{class:"Keyword"},"as"),s(),a("a",{id:"v400103862",class:"aya-hover","aya-hover-text":"Ty _",href:"#v400103862"},[a("span",{class:"LocalVar"},"A")]),s(" ⇒ "),a("a",{id:"Mian-Tm-Πη",class:"aya-hover","aya-hover-text":"λ (app f) = f",href:"#Mian-Tm-Πη"},[a("span",{class:"Constructor"},"Πη")]),s(" ("),a("a",{id:"v573200870",class:"aya-hover","aya-hover-text":"Tm _ (Π _ _)",href:"#v573200870"},[a("span",{class:"LocalVar"},"f")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#v400103862"},[a("span",{class:"LocalVar"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π _ _)",href:"#Mian-Tm-λ"},[a("span",{class:"Constructor"},"λ")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Tm (_ ▷ _) _",href:"#Mian-Tm-app"},[a("span",{class:"Constructor"},"app")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π _ _)",href:"#v573200870"},[a("span",{class:"LocalVar"},"f")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π _ _)",href:"#v573200870"},[a("span",{class:"LocalVar"},"f")]),s(`
+| _, `),a("a",{class:"aya-hover","aya-hover-text":"Ty Γ",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(),a("a",{id:"v1058876963",class:"aya-hover","aya-hover-text":"Ty _",href:"#v1058876963"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{id:"v1399701152",class:"aya-hover","aya-hover-text":"Ty (_ ▷ A)",href:"#v1399701152"},[a("span",{class:"LocalVar"},"B")]),s(" ⇒ "),a("a",{id:"Mian-Tm-subλ",class:"aya-hover","aya-hover-text":`coe 0 1 (\\ p0 ⇒ Tm _ (fording p0)) (coe 0 1 (\\ p0 ⇒ Tm _ (SubΠ σ p0)) (sub (λ t)))
+= coe 0 1 (\\ p0 ⇒ Tm _ (fording p0)) (λ (sub t))`,href:"#Mian-Tm-subλ"},[a("span",{class:"Constructor"},"subλ")]),s(" {"),a("a",{id:"v2003463579",class:"aya-hover","aya-hover-text":"Con",href:"#v2003463579"},[a("span",{class:"LocalVar"},"Δ")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Con"},[a("span",{class:"Data"},"Con")]),s("} {"),a("a",{id:"v567294307",class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v567294307"},[a("span",{class:"LocalVar"},"σ")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v1345483087"},[a("span",{class:"LocalVar"},"Γ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3c3c"},[a("span",{class:"Data"},"<<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v2003463579"},[a("span",{class:"LocalVar"},"Δ")]),s("} {"),a("a",{id:"v527829831",class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v527829831"},[a("span",{class:"LocalVar"},"A'")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Ty"},[a("span",{class:"Data"},"Ty")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v2003463579"},[a("span",{class:"LocalVar"},"Δ")]),s("} {"),a("a",{id:"v418179060",class:"aya-hover","aya-hover-text":"Ty (Δ ▷ A')",href:"#v418179060"},[a("span",{class:"LocalVar"},"B'")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Ty"},[a("span",{class:"Data"},"Ty")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v2003463579"},[a("span",{class:"LocalVar"},"Δ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v527829831"},[a("span",{class:"LocalVar"},"A'")]),s(`)}
+ (`),a("a",{id:"v777457133",class:"aya-hover","aya-hover-text":`Π (Subst A' σ) (Subst B' ((σ ∘ π₁ (id refl)) ∷ transport (Tm (_ ▷ Subst A' σ)) SubAss
+(π₂ (id refl)))) = Π A B`,href:"#v777457133"},[a("span",{class:"LocalVar"},"fording")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v527829831"},[a("span",{class:"LocalVar"},"A'")]),s(),a("a",{class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v567294307"},[a("span",{class:"LocalVar"},"σ")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Ty (_ ▷ Subst A' σ)",href:"#Mian-Ty-Subst"},[a("span",{class:"Constructor"},"Subst")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty (Δ ▷ A')",href:"#v418179060"},[a("span",{class:"LocalVar"},"B'")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+KDxhIGhyZWY9IiN2NTY3Mjk0MzA3Ij48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPs+DPC9zcGFuPjwvYT4gPGEgaHJlZj0iI01pYW4tM2MzYy3iiJgiPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+4oiYPC9zcGFuPjwvYT4gPHNwYW4gY2xhc3M9IkNhbGwiPjxhIGhyZWY9IiNNaWFuLTNjM2Mtz4DigoEiPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+z4DigoE8L3NwYW4+PC9hPiA8c3BhbiBjbGFzcz0iQ2FsbCI+KDxhIGhyZWY9IiNNaWFuLTNjM2MtaWQiPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+aWQ8L3NwYW4+PC9hPiA8YSBocmVmPSIjTWlhbi1yZWZsIj48c3BhbiBjbGFzcz0iRm4iPnJlZmw8L3NwYW4+PC9hPik8L3NwYW4+PC9zcGFuPikgPGEgaHJlZj0iI01pYW4tM2MzYy3iiLciPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+4oi3PC9zcGFuPjwvYT4gPHNwYW4gY2xhc3M9IkNhbGwiPjxhIGhyZWY9IiNNaWFuLXRyYW5zcG9ydCI+PHNwYW4gY2xhc3M9IkZuIj50cmFuc3BvcnQ8L3NwYW4+PC9hPiA8c3BhbiBjbGFzcz0iQ2FsbCI+KDxhIGhyZWY9IiNNaWFuLVRtIj48c3BhbiBjbGFzcz0iRGF0YSI+VG08L3NwYW4+PC9hPiAoPGEgaHJlZj0iI3YxMjA0Mjk2MzgzIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPl88L3NwYW4+PC9hPiA8YSBocmVmPSIjTWlhbi1Db24t4pa3Ij48c3BhbiBjbGFzcz0iQ29uc3RydWN0b3IiPuKWtzwvc3Bhbj48L2E+IDxzcGFuIGNsYXNzPSJDYWxsIj48YSBocmVmPSIjTWlhbi1UeS1TdWJzdCI+PHNwYW4gY2xhc3M9IkNvbnN0cnVjdG9yIj5TdWJzdDwvc3Bhbj48L2E+IDxhIGhyZWY9IiN2NTI3ODI5ODMxIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPkEnPC9zcGFuPjwvYT4gPGEgaHJlZj0iI3Y1NjcyOTQzMDciPjxzcGFuIGNsYXNzPSJMb2NhbFZhciI+z4M8L3NwYW4+PC9hPjwvc3Bhbj4pKTwvc3Bhbj4gPGEgaHJlZj0iI01pYW4tVHktU3ViQXNzIj48c3BhbiBjbGFzcz0iQ29uc3RydWN0b3IiPlN1YkFzczwvc3Bhbj48L2E+IDxzcGFuIGNsYXNzPSJDYWxsIj4oPGEgaHJlZj0iI01pYW4tVG0tz4DigoIiPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+z4DigoI8L3NwYW4+PC9hPiA8c3BhbiBjbGFzcz0iQ2FsbCI+KDxhIGhyZWY9IiNNaWFuLTNjM2MtaWQiPjxzcGFuIGNsYXNzPSJDb25zdHJ1Y3RvciI+aWQ8L3NwYW4+PC9hPiA8YSBocmVmPSIjTWlhbi1yZWZsIj48c3BhbiBjbGFzcz0iRm4iPnJlZmw8L3NwYW4+PC9hPik8L3NwYW4+KTwvc3Bhbj48L3NwYW4+PC9jb2RlPgo8L3ByZT4K"},"_"),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#Mian-Ty-Π"},[a("span",{class:"Constructor"},"Π")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty _",href:"#v1058876963"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty (_ ▷ A)",href:"#v1399701152"},[a("span",{class:"LocalVar"},"B")]),s(") {"),a("a",{id:"v193388045",class:"aya-hover","aya-hover-text":"Tm (Δ ▷ A') B'",href:"#v193388045"},[a("span",{class:"LocalVar"},"t")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#v2003463579"},[a("span",{class:"LocalVar"},"Δ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Con",href:"#Mian-Con-▷"},[a("span",{class:"Constructor"},"▷")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Ty Δ",href:"#v527829831"},[a("span",{class:"LocalVar"},"A'")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Ty (Δ ▷ A')",href:"#v418179060"},[a("span",{class:"LocalVar"},"B'")]),s(`}
+ : `),a("span",{class:"Keyword"},"let"),s(),a("a",{id:"v394785440",href:"#v394785440"},[a("span",{class:"LocalVar"},"ford")]),s(" := "),a("a",{class:"aya-hover","aya-hover-text":`Tm _ (Π (Subst A' σ) (Subst B' ((σ ∘ π₁ (id refl)) ∷ transport (Tm (_ ▷ Subst A'
+σ)) SubAss (π₂ (id refl))))) → Tm _ (Π A B)`,href:"#Mian-transport"},[a("span",{class:"Fn"},"transport")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Ty _ → Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3YxMjA0Mjk2MzgzIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPl88L3NwYW4+PC9hPjwvY29kZT4KPC9wcmU+Cg=="},"_"),s(") "),a("a",{class:"aya-hover","aya-hover-text":`Π (Subst A' σ) (Subst B' ((σ ∘ π₁ (id refl)) ∷ transport (Tm (_ ▷ Subst A' σ)) SubAss
+(π₂ (id refl)))) = Π A B`,href:"#v777457133"},[a("span",{class:"LocalVar"},"fording")]),s(`
+ `),a("span",{class:"Keyword"},"in"),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π A B)",href:"#v394785440"},[a("span",{class:"LocalVar"},"ford")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π (Subst A' σ) (Subst B' (ext σ A')))",href:"#Mian-transport"},[a("span",{class:"Fn"},"transport")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Ty _ → Type 0",href:"#Mian-Tm"},[a("span",{class:"Data"},"Tm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3YxMjA0Mjk2MzgzIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPl88L3NwYW4+PC9hPjwvY29kZT4KPC9wcmU+Cg=="},"_"),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"I → Ty _",href:"#Mian-Ty-SubΠ"},[a("span",{class:"Constructor"},"SubΠ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"_ << Δ",href:"#v567294307"},[a("span",{class:"LocalVar"},"σ")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Subst (Π A' B') σ)",href:"#Mian-Tm-sub"},[a("span",{class:"Constructor"},"sub")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Tm Δ (Π A' B')",href:"#Mian-Tm-λ"},[a("span",{class:"Constructor"},"λ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm (Δ ▷ A') B'",href:"#v193388045"},[a("span",{class:"LocalVar"},"t")]),s(`)))
+ `),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm _ (Π A B)",href:"#v394785440"},[a("span",{class:"LocalVar"},"ford")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":`Tm _ (Π (Subst A' σ) (Subst B' ((σ ∘ π₁ (id refl)) ∷ transport (Tm (_ ▷ Subst A'
+σ)) SubAss (π₂ (id refl)))))`,href:"#Mian-Tm-λ"},[a("span",{class:"Constructor"},"λ")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":`Tm (_ ▷ Subst A' σ) (Subst B' ((σ ∘ π₁ (id refl)) ∷ transport (Tm (_ ▷ Subst A' σ))
+SubAss (π₂ (id refl))))`,href:"#Mian-Tm-sub"},[a("span",{class:"Constructor"},"sub")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Tm (Δ ▷ A') B'",href:"#v193388045"},[a("span",{class:"LocalVar"},"t")]),s("))")]),s(`
+`)],-1),i('
An instance of type Tm Γ A corresponds to the t in the judgment Γ⊢t:A.
',1)]))}const j=V(w,[["render",S]]);export{P as __pageData,j as default};
diff --git a/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.lean.js b/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.lean.js
new file mode 100644
index 0000000..12515bc
--- /dev/null
+++ b/assets/blog_tt-in-tt-qiit.md.BjrgqciZ.lean.js
@@ -0,0 +1,67 @@
+import{_ as V,c as A,a2 as i,j as a,a as s,o as g}from"./chunks/framework.BnE-uSbk.js";const w={mounted(){const p=new Map;function v(l){const e=l.querySelectorAll("a[href]");for(const r of e){const n=r.href,y=p.get(n)??new Set;y.add(r),p.set(n,y)}for(const r of e)r.onmouseover=function(){for(const n of p.get(this.href))n.classList.add("hover-highlight")},r.onmouseout=function(){for(const n of p.get(this.href))n.classList.remove("hover-highlight")}}function x(l){return decodeURIComponent(atob(l).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const f=(l=>{const e={};return(...r)=>{const n=JSON.stringify(r);return e[n]=e[n]||l(...r)}})(x);class d{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(r=>r!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let r=this.list.find(n=>n.userCreatedFrom===e);this.dismissIfNotUsed(r)}createHoverFor(e,r,n){let y=this.list.find(o=>o.userCreatedFrom===e);if(y&&y.userClicked)return y;let M=[];const C=this.list.filter(o=>{if(this.allowAutoDismissal(o))return M.push(o),!1;const c=o.userCreatedFrom,m=e;let h=m;for(;h;){if(h===c)return!0;h=h.parentElement}for(h=c;h;){if(h===m)return!0;h=h.parentElement}return!1});M.forEach(o=>this.dismiss(o));let t=document.createElement("div");t.userCreatedFrom=e,t.innerHTML="×"+f(r),t.classList.add("AyaTooltipPopup"),v(t);let b=this;if(t.handleEvent=function(o){if(o.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let c=this.children[0];if(!c)return;let m=this;c.style.visibility="visible",c.addEventListener("click",h=>b.dismiss(m))}o.type==="mouseover"&&(this.userIsThinking=!0),o.type==="mouseout"&&(this.userIsThinking=!1,b.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),n.appendChild(t),t.style.left=`${e.offsetLeft}px`,C.length===0){const o=e.getBoundingClientRect(),c=t.getBoundingClientRect();o.bottom+c.height+30>window.innerHeight?t.style.top=`calc(${e.offsetTop-c.height+8}px - 3em)`:t.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const o=Math.max(...C.map(c=>c.offsetTop+c.offsetHeight));t.style.top=`${o+8}px`}return this.list.push(t),t}}let T=new d;function u(l){return function(){let e=this;const r=e.getAttribute("data-tooltip-text");r&&(l?T.createHoverFor(e,r,document.body):T.fireAutoDismissalFor(e))}}v(document);{let l=document.getElementsByClassName("aya-tooltip");for(let e=0;eType Theory in Type Theory using Quotient Inductive Types
',2)]))}const Pe=g(Ia,[["render",Aa],["__scopeId","data-v-26586a7a"]]),Ca={...ye,Layout(){return ge(ye.Layout,null,{"home-hero-before":()=>ge(Pe)})},enhanceApp({app:o}){o.component("Publications",Ma).component("AyaHeader",Pe)}};export{Ca as R,po as c,L as u};
diff --git a/assets/guide_fake-literate.md.5HoY67ds.js b/assets/guide_fake-literate.md.5HoY67ds.js
new file mode 100644
index 0000000..c8449e6
--- /dev/null
+++ b/assets/guide_fake-literate.md.5HoY67ds.js
@@ -0,0 +1,45 @@
+import{_ as a,c as i,a2 as n,o as e}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Fake literate mode","description":"","frontmatter":{},"headers":[],"relativePath":"guide/fake-literate.md","filePath":"guide/fake-literate.md","lastUpdated":1717700861000}'),t={name:"guide/fake-literate.md"};function l(p,s,h,k,d,r){return e(),i("div",null,s[0]||(s[0]=[n(`
The Aya compiler generates styled (e.g. with colors and text attributes) code snippets for many targets, like HTML, LaTeX, etc., and it's tempting to use the same tool but for different languages. This is what the fake literate mode is for. Let me know if you want other backend supports.
To start, install the latest version of Aya, put the following code in a file named hello.flcl:
keyword: data where;
+symbol: ≃;
+data: Int;
+constructor: zero succ;
+------
+data Int where
+ zero : Int
+ succ : Int ≃ Int
Then, run the following command to generate literate output, where you replace <AYA> with either java -jar <path-to-aya.jar> or aya depending on your installation:
You may add -o hello.tex to let it write to a file instead of printing to the console. With minimal configurations such as below, you can compile it with any LaTeX toolchain:
Use \\includeFlcl{hello} to include the generated code in your document.
`,13)]))}const E=a(t,[["render",l]]);export{c as __pageData,E as default};
diff --git a/assets/guide_fake-literate.md.5HoY67ds.lean.js b/assets/guide_fake-literate.md.5HoY67ds.lean.js
new file mode 100644
index 0000000..c8449e6
--- /dev/null
+++ b/assets/guide_fake-literate.md.5HoY67ds.lean.js
@@ -0,0 +1,45 @@
+import{_ as a,c as i,a2 as n,o as e}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Fake literate mode","description":"","frontmatter":{},"headers":[],"relativePath":"guide/fake-literate.md","filePath":"guide/fake-literate.md","lastUpdated":1717700861000}'),t={name:"guide/fake-literate.md"};function l(p,s,h,k,d,r){return e(),i("div",null,s[0]||(s[0]=[n(`
The Aya compiler generates styled (e.g. with colors and text attributes) code snippets for many targets, like HTML, LaTeX, etc., and it's tempting to use the same tool but for different languages. This is what the fake literate mode is for. Let me know if you want other backend supports.
To start, install the latest version of Aya, put the following code in a file named hello.flcl:
keyword: data where;
+symbol: ≃;
+data: Int;
+constructor: zero succ;
+------
+data Int where
+ zero : Int
+ succ : Int ≃ Int
Then, run the following command to generate literate output, where you replace <AYA> with either java -jar <path-to-aya.jar> or aya depending on your installation:
You may add -o hello.tex to let it write to a file instead of printing to the console. With minimal configurations such as below, you can compile it with any LaTeX toolchain:
Use \\includeFlcl{hello} to include the generated code in your document.
`,13)]))}const E=a(t,[["render",l]]);export{c as __pageData,E as default};
diff --git a/assets/guide_haskeller-tutorial.md.GKsyNqV0.js b/assets/guide_haskeller-tutorial.md.GKsyNqV0.js
new file mode 100644
index 0000000..5febc1e
--- /dev/null
+++ b/assets/guide_haskeller-tutorial.md.GKsyNqV0.js
@@ -0,0 +1,75 @@
+import{_ as F,c as N,a2 as h,j as a,a as s,o as M}from"./chunks/framework.BnE-uSbk.js";const V={mounted(){const d=new Map;function y(r){const e=r.querySelectorAll("a[href]");for(const t of e){const o=t.href,p=d.get(o)??new Set;p.add(t),d.set(o,p)}for(const t of e)t.onmouseover=function(){for(const o of d.get(this.href))o.classList.add("hover-highlight")},t.onmouseout=function(){for(const o of d.get(this.href))o.classList.remove("hover-highlight")}}function u(r){return decodeURIComponent(atob(r).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const k=(r=>{const e={};return(...t)=>{const o=JSON.stringify(t);return e[o]=e[o]||r(...t)}})(u);class f{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(t=>t!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let t=this.list.find(o=>o.userCreatedFrom===e);this.dismissIfNotUsed(t)}createHoverFor(e,t,o){let p=this.list.find(i=>i.userCreatedFrom===e);if(p&&p.userClicked)return p;let x=[];const b=this.list.filter(i=>{if(this.allowAutoDismissal(i))return x.push(i),!1;const l=i.userCreatedFrom,v=e;let c=v;for(;c;){if(c===l)return!0;c=c.parentElement}for(c=l;c;){if(c===v)return!0;c=c.parentElement}return!1});x.forEach(i=>this.dismiss(i));let n=document.createElement("div");n.userCreatedFrom=e,n.innerHTML="×"+k(t),n.classList.add("AyaTooltipPopup"),y(n);let A=this;if(n.handleEvent=function(i){if(i.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let l=this.children[0];if(!l)return;let v=this;l.style.visibility="visible",l.addEventListener("click",c=>A.dismiss(v))}i.type==="mouseover"&&(this.userIsThinking=!0),i.type==="mouseout"&&(this.userIsThinking=!1,A.dismissIfNotUsed(this))},n.addEventListener("click",n),n.addEventListener("mouseover",n),n.addEventListener("mouseout",n),o.appendChild(n),n.style.left=`${e.offsetLeft}px`,b.length===0){const i=e.getBoundingClientRect(),l=n.getBoundingClientRect();i.bottom+l.height+30>window.innerHeight?n.style.top=`calc(${e.offsetTop-l.height+8}px - 3em)`:n.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const i=Math.max(...b.map(l=>l.offsetTop+l.offsetHeight));n.style.top=`${i+8}px`}return this.list.push(n),n}}let g=new f;function m(r){return function(){let e=this;const t=e.getAttribute("data-tooltip-text");t&&(r?g.createHoverFor(e,t,document.body):g.fireAutoDismissalFor(e))}}y(document);{let r=document.getElementsByClassName("aya-tooltip");for(let e=0;eSo you know some Haskell
Great. I expect you to know something about GHCi and algebraic data types. This is an Aya tutorial for Haskell programmers. If you find a bug, open an issue on GitHub!
Aya has a REPL that works similar to GHCi. You can start it by running aya -i in your terminal, and you can start typing definitions or expressions.
bash
aya -i
If you're using jar with java, use the following instead:
bash
java --enable-preview -jar cli-fatjar.jar -i
In the REPL, you can use :l to load a file, :q to quit, and :? to get help. Use :t to show the type. Since it's dependent type, you can toggle normalization levels by :normalize followed by NF, WHNF, or NULL (don't normalize).
To work multiline, use the pair :{ and :} -- same as GHCi.
Aya supports pretty-printing of any terms, including ✨lambdas✨. Note that Aya does not automatically support generic lambdas, so typing \\x => x would not work. You need to specify the type of x, like \\(x : Int) => x.
Aya support fn as an alias to \\ instead of λ, similar to Coq and Lean (but not Agda). This is because users (especially mathematicians) are likely to use λ as a variable name. Similarly, we used Fn over Pi or Π for the same reason.
Read project-tutorial, it is very short. It is recommended to practice the following with an Aya project in VSCode, see vscode-tutorial.
About modules:
Aya module names are separated by ::, not ..
Aya infers the module names automagically, using the same rule as of Haskell.
Aya imports (import X) are qualified by default, use open import X to unqualify. This is short for import X followed by open X.
Aya supports restricted import open import X using (x) (this only imports x from X) you may also use open import X hiding (x) to import everything except x from X.
Aya supports renamed import open import X using (x as y) and the meaning is obvious.
We don't enforce capitalization of constructors. The constructors need to be qualified (like Nat::zero) to access. As you may expect, Nat automatically becomes a module, so we can use open and public open to unqualify the constructors.
Bonus: if you define a data type that looks likeNat, then you can use numeric literals.
Functions are defined with def, followed by pattern matching. Consider this natural number addition in Haskell (intentionally not called + to avoid name clash with Prelude):
haskell
(<+>) :: Nat -> Nat -> Nat
+Zero <+> n = n
+Suc m <+> n = Suc (m <+> n)
+
+infixl 6 <+>
There are plenty of differences. Let's go through them one by one.
The infixl declares <+> to be a left-associative infix operator. Other options include infix, infixr, fixl, and fixr. Without it, the function will work the same as normal function. Unlike Haskell, we do not distinguish "operator" names and "function" names.
We do not use a number to denote precedence, but a partial order. This allows arbitrary insertion of new precedence level into previously defined ones. Say you want <+> to have a lower precedence than <*>, you can do:
The parameters and the return type are separated using :. The parameter types can be written directly, without ->. Aya allow naming the parameters like this:
def oh (x : Nat) : Nat
These names can be used for one-linear function bodies:
Aya supports a painless version of the section syntax, where the top-level does not need parentheses. See the following REPL output (the underscored names are internally generated variable names. If you have an idea on how to make them better, open an issue and let's discuss!).
Type parameters have to be explicitly qualified using curly braces.
Curly braces denote parameters that are omitted (and will be inferred by type checker) in the pattern matching and invocations. So, parentheses denote parameters that are not omitted.
Apart from Type, we also have Set, and ISet. For now, don't use the others.
Type constructors are like {F : Type -> Type} (and yes, the -> denotes function types, works for both values and types), very obvious. Definition of Maybe in Aya:
",3),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Maybe",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(" ("),a("a",{id:"v304354378",class:"aya-hover","aya-hover-text":"Type 0",href:"#v304354378"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| `),a("a",{id:"Mian-Maybe-nothing",class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(`
+| `),a("a",{id:"Mian-Maybe-just",class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v304354378"},[a("span",{class:"LocalVar"},"A")])]),s(`
+`)],-1),a("p",null,[s("Here, "),a("code",null,"(A : Type)"),s(" is an explicit parameter, because you write "),a("code",null,"Maybe Nat"),s(", not just "),a("code",null,"Maybe"),s(".")],-1),a("p",null,[s("There is a way to automagically insert the implicit parameters -- the "),a("code",null,"variable"),s(" keyword.")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v854487022",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`
+
+`),a("span",{class:"Comment"},"// Now, since you are using A, so Aya inserts {A : Type}"),s(`
+`),a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+aWQ8L2NvZGU+IHNoYWRvd3MgYSBwcmV2aW91cyBsb2NhbCBkZWZpbml0aW9uIGZyb20gb3V0ZXIgc2NvcGU8L2NvZGU+CjwvcHJlPgo="},[a("span",{class:"Warning"},[a("a",{id:"Mian-3aNoExport-id",class:"aya-hover","aya-hover-text":"A",href:"#Mian-3aNoExport-id"},[a("span",{class:"Fn"},"id")])])]),s(" ("),a("a",{id:"v131872530",class:"aya-hover","aya-hover-text":"A",href:"#v131872530"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v131872530"},[a("span",{class:"LocalVar"},"x")])]),s(`
+`)],-1),a("p",null,"Aya supports type aliases as functions. For example, we may define the type of binary operators as a function:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-BinOp",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-BinOp"},[a("span",{class:"Fn"},"BinOp")]),s(" ("),a("a",{id:"v98826337",class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")])]),s(`
+`)],-1),a("p",null,[s("Then, we can define "),a("code",null,"<+>"),s(" as:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixl"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+Jmx0OysmZ3Q7PC9jb2RlPiBzaGFkb3dzIGEgcHJldmlvdXMgbG9jYWwgZGVmaW5pdGlvbiBmcm9tIG91dGVyIHNjb3BlPC9jb2RlPgo8L3ByZT4K"},[a("span",{class:"Warning"},[a("a",{id:"Mian-3aNoExport-3c2b3e",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-3c2b3e"},[a("span",{class:"Fn"},"<+>")])])]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-BinOp"},[a("span",{class:"Fn"},"BinOp")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v573958827",class:"aya-hover","aya-hover-text":"Nat",href:"#v573958827"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v573958827"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v391135083",class:"aya-hover","aya-hover-text":"Nat",href:"#v391135083"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v1003292107",class:"aya-hover","aya-hover-text":"Nat",href:"#v1003292107"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v391135083"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-3c2b3e"},[a("span",{class:"Fn"},"<+>")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1003292107"},[a("span",{class:"LocalVar"},"n")]),s(")")]),s(`
+`)],-1),a("h2",{id:"type-families",tabindex:"-1"},[s("Type families "),a("a",{class:"header-anchor",href:"#type-families","aria-label":'Permalink to "Type families"'},"")],-1),a("p",null,[s("In Aya, type families are functions. Consider the following code (they are using the "),a("code",null,"variable A"),s(" defined above):")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Comment"},"// Unit type"),s(`
+`),a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Unit",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Unit"},[a("span",{class:"Data"},"Unit")]),s(" | "),a("a",{id:"Mian-Unit-unit",class:"aya-hover","aya-hover-text":"Unit",href:"#Mian-Unit-unit"},[a("span",{class:"Constructor"},"unit")]),s(`
+
+`),a("span",{class:"Comment"},"// A type family"),s(`
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-FromJust",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(" ("),a("a",{id:"v914374969",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v914374969"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("span",{class:"Keyword"},"Type"),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{id:"v1930240356",class:"aya-hover","aya-hover-text":"A",href:"#v1930240356"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Unit"},[a("span",{class:"Data"},"Unit")]),s(`
+
+`),a("span",{class:"Comment"},"// A function that uses the type family"),s(`
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-fromJust",class:"aya-hover","aya-hover-text":"FromJust x",href:"#Mian-fromJust"},[a("span",{class:"Fn"},"fromJust")]),s(" ("),a("a",{id:"v1323434987",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"x")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{id:"v1365767549",class:"aya-hover","aya-hover-text":"A",href:"#v1365767549"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1365767549"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Unit",href:"#Mian-Unit-unit"},[a("span",{class:"Constructor"},"unit")])]),s(`
+`)],-1),a("p",null,[s("And "),a("code",null,"fromJust (just a)"),s(" will evaluate to "),a("code",null,"a"),s(". In Haskell, you need to use some language extensions alongside some scary keywords. These functions are available in constructors, too:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Example",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Example"},[a("span",{class:"Data"},"Example")]),s(" ("),a("a",{id:"v1358343316",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| `),a("a",{id:"Mian-Example-cons",class:"aya-hover","aya-hover-text":"Example A",href:"#Mian-Example-cons"},[a("span",{class:"Constructor"},"cons")]),s(" ("),a("a",{id:"v1824837049",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1824837049"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1824837049"},[a("span",{class:"LocalVar"},"x")]),s(")")]),s(`
+`)],-1),h(`
It is recommended to play with it in the REPL to get a feel of it.
There is a famous example of dependent types in Haskell -- the sized vector type:
haskell
{-# LANGUAGE GADTs #-}
+{-# LANGUAGE DataKinds #-}
+-- Maybe you need more, I don't remember exactly
+
+data Vec :: Nat -> Type -> Type where
+ Nil :: Vec Zero a
+ (:<) :: a -> Vec n a -> Vec (Suc n) a
+infixr :<
In Aya, we have a better syntax:
`,4),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Vec",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{id:"v442199874",class:"aya-hover","aya-hover-text":"Nat",href:"#v442199874"},[a("span",{class:"LocalVar"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") ("),a("a",{id:"v1345900725",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1345900725"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| 0, `),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v839998248",class:"aya-hover","aya-hover-text":"Type 0",href:"#v839998248"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("a",{id:"Mian-Vec-nil",class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+bjwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v102174918",class:"aya-hover","aya-hover-text":"Nat",href:"#v102174918"},[a("span",{class:"LocalVar"},"n")])])]),s(", "),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v52514534",class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-Vec-3a3c",class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v102174918"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")]),s(")")]),s(`
+`)],-1),a("p",null,[s("The "),a("code",null,":<"),s(" constructor is defined as a right-associative infix operator. And yes, you can define like vector append painlessly:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v375457936",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{id:"v710190911",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+
+`),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-2b2b",class:"aya-hover","aya-hover-text":"Vec (n <+> m) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3c2b3e"},[a("span",{class:"Fn"},"<+>")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(", "),a("a",{id:"v375466577",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v375466577"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v375466577"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v127791068",class:"aya-hover","aya-hover-text":"A",href:"#v127791068"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{id:"v405896924",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v405896924"},[a("span",{class:"LocalVar"},"xs")]),s(", "),a("a",{id:"v1309335839",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1309335839"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v127791068"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc (?n A x xs ys n m)) (?A A x xs ys n m)",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v405896924"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n A x xs ys n m <+> ?m A x xs ys n m) (?A A x xs ys n m)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1309335839"},[a("span",{class:"LocalVar"},"ys")]),s(`
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")])]),s(`
+`)],-1),h(`
There is one more bonus: in Aya, you may modify the definition of <+> to be:
overlap def infixl <+> Nat Nat : Nat
+| 0, n => n
+| n, 0 => n
+| suc m, n => suc (m <+> n)
It says we not only compute 0 + n = n, but when the first parameter is neither 0 nor suc, we may take a look at the second parameter and seek for other potential computations. This is completely useless at runtime, but very good for type checking. For instance, we may want a Vec of size n, and what we have is some Vec of size n + 0. Then having n + 0 to directly reduce to n is very useful, otherwise we will need to write a conversion function that does nothing but changes the type, or use unsafeCoerce.
With n + 0 = n judgmentally, we now have more possibilities. For instance, we can make xs ++ nil = xs. This involves in two steps: we first turni ++ into a overlap def, then we add the following clause to ++:
`,9)]))}const D=F(V,[["render",T]]);export{C as __pageData,D as default};
diff --git a/assets/guide_haskeller-tutorial.md.GKsyNqV0.lean.js b/assets/guide_haskeller-tutorial.md.GKsyNqV0.lean.js
new file mode 100644
index 0000000..5febc1e
--- /dev/null
+++ b/assets/guide_haskeller-tutorial.md.GKsyNqV0.lean.js
@@ -0,0 +1,75 @@
+import{_ as F,c as N,a2 as h,j as a,a as s,o as M}from"./chunks/framework.BnE-uSbk.js";const V={mounted(){const d=new Map;function y(r){const e=r.querySelectorAll("a[href]");for(const t of e){const o=t.href,p=d.get(o)??new Set;p.add(t),d.set(o,p)}for(const t of e)t.onmouseover=function(){for(const o of d.get(this.href))o.classList.add("hover-highlight")},t.onmouseout=function(){for(const o of d.get(this.href))o.classList.remove("hover-highlight")}}function u(r){return decodeURIComponent(atob(r).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const k=(r=>{const e={};return(...t)=>{const o=JSON.stringify(t);return e[o]=e[o]||r(...t)}})(u);class f{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(t=>t!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let t=this.list.find(o=>o.userCreatedFrom===e);this.dismissIfNotUsed(t)}createHoverFor(e,t,o){let p=this.list.find(i=>i.userCreatedFrom===e);if(p&&p.userClicked)return p;let x=[];const b=this.list.filter(i=>{if(this.allowAutoDismissal(i))return x.push(i),!1;const l=i.userCreatedFrom,v=e;let c=v;for(;c;){if(c===l)return!0;c=c.parentElement}for(c=l;c;){if(c===v)return!0;c=c.parentElement}return!1});x.forEach(i=>this.dismiss(i));let n=document.createElement("div");n.userCreatedFrom=e,n.innerHTML="×"+k(t),n.classList.add("AyaTooltipPopup"),y(n);let A=this;if(n.handleEvent=function(i){if(i.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let l=this.children[0];if(!l)return;let v=this;l.style.visibility="visible",l.addEventListener("click",c=>A.dismiss(v))}i.type==="mouseover"&&(this.userIsThinking=!0),i.type==="mouseout"&&(this.userIsThinking=!1,A.dismissIfNotUsed(this))},n.addEventListener("click",n),n.addEventListener("mouseover",n),n.addEventListener("mouseout",n),o.appendChild(n),n.style.left=`${e.offsetLeft}px`,b.length===0){const i=e.getBoundingClientRect(),l=n.getBoundingClientRect();i.bottom+l.height+30>window.innerHeight?n.style.top=`calc(${e.offsetTop-l.height+8}px - 3em)`:n.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const i=Math.max(...b.map(l=>l.offsetTop+l.offsetHeight));n.style.top=`${i+8}px`}return this.list.push(n),n}}let g=new f;function m(r){return function(){let e=this;const t=e.getAttribute("data-tooltip-text");t&&(r?g.createHoverFor(e,t,document.body):g.fireAutoDismissalFor(e))}}y(document);{let r=document.getElementsByClassName("aya-tooltip");for(let e=0;eSo you know some Haskell
Great. I expect you to know something about GHCi and algebraic data types. This is an Aya tutorial for Haskell programmers. If you find a bug, open an issue on GitHub!
Aya has a REPL that works similar to GHCi. You can start it by running aya -i in your terminal, and you can start typing definitions or expressions.
bash
aya -i
If you're using jar with java, use the following instead:
bash
java --enable-preview -jar cli-fatjar.jar -i
In the REPL, you can use :l to load a file, :q to quit, and :? to get help. Use :t to show the type. Since it's dependent type, you can toggle normalization levels by :normalize followed by NF, WHNF, or NULL (don't normalize).
To work multiline, use the pair :{ and :} -- same as GHCi.
Aya supports pretty-printing of any terms, including ✨lambdas✨. Note that Aya does not automatically support generic lambdas, so typing \\x => x would not work. You need to specify the type of x, like \\(x : Int) => x.
Aya support fn as an alias to \\ instead of λ, similar to Coq and Lean (but not Agda). This is because users (especially mathematicians) are likely to use λ as a variable name. Similarly, we used Fn over Pi or Π for the same reason.
Read project-tutorial, it is very short. It is recommended to practice the following with an Aya project in VSCode, see vscode-tutorial.
About modules:
Aya module names are separated by ::, not ..
Aya infers the module names automagically, using the same rule as of Haskell.
Aya imports (import X) are qualified by default, use open import X to unqualify. This is short for import X followed by open X.
Aya supports restricted import open import X using (x) (this only imports x from X) you may also use open import X hiding (x) to import everything except x from X.
Aya supports renamed import open import X using (x as y) and the meaning is obvious.
We don't enforce capitalization of constructors. The constructors need to be qualified (like Nat::zero) to access. As you may expect, Nat automatically becomes a module, so we can use open and public open to unqualify the constructors.
Bonus: if you define a data type that looks likeNat, then you can use numeric literals.
Functions are defined with def, followed by pattern matching. Consider this natural number addition in Haskell (intentionally not called + to avoid name clash with Prelude):
haskell
(<+>) :: Nat -> Nat -> Nat
+Zero <+> n = n
+Suc m <+> n = Suc (m <+> n)
+
+infixl 6 <+>
There are plenty of differences. Let's go through them one by one.
The infixl declares <+> to be a left-associative infix operator. Other options include infix, infixr, fixl, and fixr. Without it, the function will work the same as normal function. Unlike Haskell, we do not distinguish "operator" names and "function" names.
We do not use a number to denote precedence, but a partial order. This allows arbitrary insertion of new precedence level into previously defined ones. Say you want <+> to have a lower precedence than <*>, you can do:
The parameters and the return type are separated using :. The parameter types can be written directly, without ->. Aya allow naming the parameters like this:
def oh (x : Nat) : Nat
These names can be used for one-linear function bodies:
Aya supports a painless version of the section syntax, where the top-level does not need parentheses. See the following REPL output (the underscored names are internally generated variable names. If you have an idea on how to make them better, open an issue and let's discuss!).
Type parameters have to be explicitly qualified using curly braces.
Curly braces denote parameters that are omitted (and will be inferred by type checker) in the pattern matching and invocations. So, parentheses denote parameters that are not omitted.
Apart from Type, we also have Set, and ISet. For now, don't use the others.
Type constructors are like {F : Type -> Type} (and yes, the -> denotes function types, works for both values and types), very obvious. Definition of Maybe in Aya:
",3),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Maybe",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(" ("),a("a",{id:"v304354378",class:"aya-hover","aya-hover-text":"Type 0",href:"#v304354378"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| `),a("a",{id:"Mian-Maybe-nothing",class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(`
+| `),a("a",{id:"Mian-Maybe-just",class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v304354378"},[a("span",{class:"LocalVar"},"A")])]),s(`
+`)],-1),a("p",null,[s("Here, "),a("code",null,"(A : Type)"),s(" is an explicit parameter, because you write "),a("code",null,"Maybe Nat"),s(", not just "),a("code",null,"Maybe"),s(".")],-1),a("p",null,[s("There is a way to automagically insert the implicit parameters -- the "),a("code",null,"variable"),s(" keyword.")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v854487022",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`
+
+`),a("span",{class:"Comment"},"// Now, since you are using A, so Aya inserts {A : Type}"),s(`
+`),a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+aWQ8L2NvZGU+IHNoYWRvd3MgYSBwcmV2aW91cyBsb2NhbCBkZWZpbml0aW9uIGZyb20gb3V0ZXIgc2NvcGU8L2NvZGU+CjwvcHJlPgo="},[a("span",{class:"Warning"},[a("a",{id:"Mian-3aNoExport-id",class:"aya-hover","aya-hover-text":"A",href:"#Mian-3aNoExport-id"},[a("span",{class:"Fn"},"id")])])]),s(" ("),a("a",{id:"v131872530",class:"aya-hover","aya-hover-text":"A",href:"#v131872530"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v131872530"},[a("span",{class:"LocalVar"},"x")])]),s(`
+`)],-1),a("p",null,"Aya supports type aliases as functions. For example, we may define the type of binary operators as a function:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-BinOp",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-BinOp"},[a("span",{class:"Fn"},"BinOp")]),s(" ("),a("a",{id:"v98826337",class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v98826337"},[a("span",{class:"LocalVar"},"A")])]),s(`
+`)],-1),a("p",null,[s("Then, we can define "),a("code",null,"<+>"),s(" as:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixl"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+Jmx0OysmZ3Q7PC9jb2RlPiBzaGFkb3dzIGEgcHJldmlvdXMgbG9jYWwgZGVmaW5pdGlvbiBmcm9tIG91dGVyIHNjb3BlPC9jb2RlPgo8L3ByZT4K"},[a("span",{class:"Warning"},[a("a",{id:"Mian-3aNoExport-3c2b3e",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-3c2b3e"},[a("span",{class:"Fn"},"<+>")])])]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-BinOp"},[a("span",{class:"Fn"},"BinOp")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v573958827",class:"aya-hover","aya-hover-text":"Nat",href:"#v573958827"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v573958827"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v391135083",class:"aya-hover","aya-hover-text":"Nat",href:"#v391135083"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v1003292107",class:"aya-hover","aya-hover-text":"Nat",href:"#v1003292107"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v391135083"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-3c2b3e"},[a("span",{class:"Fn"},"<+>")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1003292107"},[a("span",{class:"LocalVar"},"n")]),s(")")]),s(`
+`)],-1),a("h2",{id:"type-families",tabindex:"-1"},[s("Type families "),a("a",{class:"header-anchor",href:"#type-families","aria-label":'Permalink to "Type families"'},"")],-1),a("p",null,[s("In Aya, type families are functions. Consider the following code (they are using the "),a("code",null,"variable A"),s(" defined above):")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Comment"},"// Unit type"),s(`
+`),a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Unit",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Unit"},[a("span",{class:"Data"},"Unit")]),s(" | "),a("a",{id:"Mian-Unit-unit",class:"aya-hover","aya-hover-text":"Unit",href:"#Mian-Unit-unit"},[a("span",{class:"Constructor"},"unit")]),s(`
+
+`),a("span",{class:"Comment"},"// A type family"),s(`
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-FromJust",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(" ("),a("a",{id:"v914374969",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v914374969"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("span",{class:"Keyword"},"Type"),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{id:"v1930240356",class:"aya-hover","aya-hover-text":"A",href:"#v1930240356"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Unit"},[a("span",{class:"Data"},"Unit")]),s(`
+
+`),a("span",{class:"Comment"},"// A function that uses the type family"),s(`
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-fromJust",class:"aya-hover","aya-hover-text":"FromJust x",href:"#Mian-fromJust"},[a("span",{class:"Fn"},"fromJust")]),s(" ("),a("a",{id:"v1323434987",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"x")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-just"},[a("span",{class:"Constructor"},"just")]),s(),a("a",{id:"v1365767549",class:"aya-hover","aya-hover-text":"A",href:"#v1365767549"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1365767549"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#Mian-Maybe-nothing"},[a("span",{class:"Constructor"},"nothing")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Unit",href:"#Mian-Unit-unit"},[a("span",{class:"Constructor"},"unit")])]),s(`
+`)],-1),a("p",null,[s("And "),a("code",null,"fromJust (just a)"),s(" will evaluate to "),a("code",null,"a"),s(". In Haskell, you need to use some language extensions alongside some scary keywords. These functions are available in constructors, too:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Example",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Example"},[a("span",{class:"Data"},"Example")]),s(" ("),a("a",{id:"v1358343316",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| `),a("a",{id:"Mian-Example-cons",class:"aya-hover","aya-hover-text":"Example A",href:"#Mian-Example-cons"},[a("span",{class:"Constructor"},"cons")]),s(" ("),a("a",{id:"v1824837049",class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1824837049"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Maybe"},[a("span",{class:"Data"},"Maybe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1358343316"},[a("span",{class:"LocalVar"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-FromJust"},[a("span",{class:"Fn"},"FromJust")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Maybe A",href:"#v1824837049"},[a("span",{class:"LocalVar"},"x")]),s(")")]),s(`
+`)],-1),h(`
It is recommended to play with it in the REPL to get a feel of it.
There is a famous example of dependent types in Haskell -- the sized vector type:
haskell
{-# LANGUAGE GADTs #-}
+{-# LANGUAGE DataKinds #-}
+-- Maybe you need more, I don't remember exactly
+
+data Vec :: Nat -> Type -> Type where
+ Nil :: Vec Zero a
+ (:<) :: a -> Vec n a -> Vec (Suc n) a
+infixr :<
In Aya, we have a better syntax:
`,4),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Vec",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{id:"v442199874",class:"aya-hover","aya-hover-text":"Nat",href:"#v442199874"},[a("span",{class:"LocalVar"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") ("),a("a",{id:"v1345900725",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1345900725"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| 0, `),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v839998248",class:"aya-hover","aya-hover-text":"Type 0",href:"#v839998248"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("a",{id:"Mian-Vec-nil",class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+bjwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v102174918",class:"aya-hover","aya-hover-text":"Nat",href:"#v102174918"},[a("span",{class:"LocalVar"},"n")])])]),s(", "),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v52514534",class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-Vec-3a3c",class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v102174918"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v52514534"},[a("span",{class:"LocalVar"},"A")]),s(")")]),s(`
+`)],-1),a("p",null,[s("The "),a("code",null,":<"),s(" constructor is defined as a right-associative infix operator. And yes, you can define like vector append painlessly:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v375457936",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{id:"v710190911",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+
+`),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-2b2b",class:"aya-hover","aya-hover-text":"Vec (n <+> m) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v710190911"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3c2b3e"},[a("span",{class:"Fn"},"<+>")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v375457936"},[a("span",{class:"Generalized"},"m")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v854487022"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(", "),a("a",{id:"v375466577",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v375466577"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v375466577"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v127791068",class:"aya-hover","aya-hover-text":"A",href:"#v127791068"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{id:"v405896924",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v405896924"},[a("span",{class:"LocalVar"},"xs")]),s(", "),a("a",{id:"v1309335839",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1309335839"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v127791068"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc (?n A x xs ys n m)) (?A A x xs ys n m)",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v405896924"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n A x xs ys n m <+> ?m A x xs ys n m) (?A A x xs ys n m)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1309335839"},[a("span",{class:"LocalVar"},"ys")]),s(`
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")])]),s(`
+`)],-1),h(`
There is one more bonus: in Aya, you may modify the definition of <+> to be:
overlap def infixl <+> Nat Nat : Nat
+| 0, n => n
+| n, 0 => n
+| suc m, n => suc (m <+> n)
It says we not only compute 0 + n = n, but when the first parameter is neither 0 nor suc, we may take a look at the second parameter and seek for other potential computations. This is completely useless at runtime, but very good for type checking. For instance, we may want a Vec of size n, and what we have is some Vec of size n + 0. Then having n + 0 to directly reduce to n is very useful, otherwise we will need to write a conversion function that does nothing but changes the type, or use unsafeCoerce.
With n + 0 = n judgmentally, we now have more possibilities. For instance, we can make xs ++ nil = xs. This involves in two steps: we first turni ++ into a overlap def, then we add the following clause to ++:
`,9)]))}const D=F(V,[["render",T]]);export{C as __pageData,D as default};
diff --git a/assets/guide_index.md.Bb5oyrEG.js b/assets/guide_index.md.Bb5oyrEG.js
new file mode 100644
index 0000000..7c9b32c
--- /dev/null
+++ b/assets/guide_index.md.Bb5oyrEG.js
@@ -0,0 +1 @@
+import{_ as a,c as t,a2 as r,o as i}from"./chunks/framework.BnE-uSbk.js";const f=JSON.parse('{"title":"The Aya Prover","description":"","frontmatter":{},"headers":[],"relativePath":"guide/index.md","filePath":"guide/index.md","lastUpdated":1717718914000}'),l={name:"guide/index.md"};function n(o,e,s,h,d,p){return i(),t("div",null,e[0]||(e[0]=[r('
Aya is a programming language and an interactive proof assistant designed for type-directed programming and formalizing math.
The type system of Aya has the following highlights:
Set-level cubical features so funExt and quotients are available without axioms (like Agda, redtt, and Arend but not higher-dimensional),
Overlapping and order-independent pattern matching makes simple functions compute better,
Practical functional programming features similar to Haskell and Idris: dependent pattern matching, typed holes, enchanted synthesis of implicit arguments.
The implementation of the Aya compiler has the following highlights:
Efficient type checking by JIT-compiling well-typed definitions to JVM higher-order abstract syntax, so substitution does not traverse terms,
Convenient interactive tools such as a language server for VSCode, a REPL, and hyperlinked document generation (demo),
Pre-compiled binary release.
',7)]))}const g=a(l,[["render",n]]);export{f as __pageData,g as default};
diff --git a/assets/guide_index.md.Bb5oyrEG.lean.js b/assets/guide_index.md.Bb5oyrEG.lean.js
new file mode 100644
index 0000000..7c9b32c
--- /dev/null
+++ b/assets/guide_index.md.Bb5oyrEG.lean.js
@@ -0,0 +1 @@
+import{_ as a,c as t,a2 as r,o as i}from"./chunks/framework.BnE-uSbk.js";const f=JSON.parse('{"title":"The Aya Prover","description":"","frontmatter":{},"headers":[],"relativePath":"guide/index.md","filePath":"guide/index.md","lastUpdated":1717718914000}'),l={name:"guide/index.md"};function n(o,e,s,h,d,p){return i(),t("div",null,e[0]||(e[0]=[r('
Aya is a programming language and an interactive proof assistant designed for type-directed programming and formalizing math.
The type system of Aya has the following highlights:
Set-level cubical features so funExt and quotients are available without axioms (like Agda, redtt, and Arend but not higher-dimensional),
Overlapping and order-independent pattern matching makes simple functions compute better,
Practical functional programming features similar to Haskell and Idris: dependent pattern matching, typed holes, enchanted synthesis of implicit arguments.
The implementation of the Aya compiler has the following highlights:
Efficient type checking by JIT-compiling well-typed definitions to JVM higher-order abstract syntax, so substitution does not traverse terms,
Convenient interactive tools such as a language server for VSCode, a REPL, and hyperlinked document generation (demo),
Pre-compiled binary release.
',7)]))}const g=a(l,[["render",n]]);export{f as __pageData,g as default};
diff --git a/assets/guide_install.md.Cs_zw_W1.js b/assets/guide_install.md.Cs_zw_W1.js
new file mode 100644
index 0000000..eae799d
--- /dev/null
+++ b/assets/guide_install.md.Cs_zw_W1.js
@@ -0,0 +1,26 @@
+import{_ as s,c as i,a2 as e,o as t}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Install Aya","description":"","frontmatter":{},"headers":[],"relativePath":"guide/install.md","filePath":"guide/install.md","lastUpdated":1717718914000}'),n={name:"guide/install.md"};function l(r,a,h,p,o,d){return t(),i("div",null,a[0]||(a[0]=[e(`
At this stage of development, we recommend using the nightly version of Aya. Go to GitHub Release, there will be a plenty of files. It's updated per-commit in the main branch, but the release date displayed is very old and is an issue of GitHub itself.
Checking the section below that fits your platform. After the installation, run aya --help for general instructions and aya -i to start an interactive REPL. If you chose the jlink version, the bin folder contains the executable scripts.
Here's a hands-on script I wrote to (re)install Aya to $AYA_PREFIX (define the variable somewhere or replace with your preferred prefix, e.g. /opt/aya) on Linux x64:
Clone the repository. Then, run build with ./gradlew followed by a task name. If you have problems downloading dependencies (like you are in China), check out how to let gradle use a proxy.
bash
# build Aya and its language server as applications to \`ide-lsp/build/image/current\`
+# the image is usable in Java-free environments
+./gradlew jlinkAya --rerun-tasks
+# build Aya and its language server as executable
+# jars to <project>/build/libs/<project>-<version>-fat.jar
+./gradlew fatJar
+# build a platform-dependent installer for Aya and its language
+# server with the jlink artifacts to ide-lsp/build/jpackage
+# requires https://wixtoolset.org/releases on Windows
+./gradlew jpackage
+# run tests and generate coverage report to build/reports
+./gradlew testCodeCoverageReport
+# (Windows only) show the coverage report in your default browser
+./gradlew showCCR
Gradle supports short-handed task names, so you can run ./gradlew fJ to invoke fatJar, tCCR to invoke testCodeCoverageReport, and so on.
`,23)]))}const y=s(n,[["render",l]]);export{c as __pageData,y as default};
diff --git a/assets/guide_install.md.Cs_zw_W1.lean.js b/assets/guide_install.md.Cs_zw_W1.lean.js
new file mode 100644
index 0000000..eae799d
--- /dev/null
+++ b/assets/guide_install.md.Cs_zw_W1.lean.js
@@ -0,0 +1,26 @@
+import{_ as s,c as i,a2 as e,o as t}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Install Aya","description":"","frontmatter":{},"headers":[],"relativePath":"guide/install.md","filePath":"guide/install.md","lastUpdated":1717718914000}'),n={name:"guide/install.md"};function l(r,a,h,p,o,d){return t(),i("div",null,a[0]||(a[0]=[e(`
At this stage of development, we recommend using the nightly version of Aya. Go to GitHub Release, there will be a plenty of files. It's updated per-commit in the main branch, but the release date displayed is very old and is an issue of GitHub itself.
Checking the section below that fits your platform. After the installation, run aya --help for general instructions and aya -i to start an interactive REPL. If you chose the jlink version, the bin folder contains the executable scripts.
Here's a hands-on script I wrote to (re)install Aya to $AYA_PREFIX (define the variable somewhere or replace with your preferred prefix, e.g. /opt/aya) on Linux x64:
Clone the repository. Then, run build with ./gradlew followed by a task name. If you have problems downloading dependencies (like you are in China), check out how to let gradle use a proxy.
bash
# build Aya and its language server as applications to \`ide-lsp/build/image/current\`
+# the image is usable in Java-free environments
+./gradlew jlinkAya --rerun-tasks
+# build Aya and its language server as executable
+# jars to <project>/build/libs/<project>-<version>-fat.jar
+./gradlew fatJar
+# build a platform-dependent installer for Aya and its language
+# server with the jlink artifacts to ide-lsp/build/jpackage
+# requires https://wixtoolset.org/releases on Windows
+./gradlew jpackage
+# run tests and generate coverage report to build/reports
+./gradlew testCodeCoverageReport
+# (Windows only) show the coverage report in your default browser
+./gradlew showCCR
Gradle supports short-handed task names, so you can run ./gradlew fJ to invoke fatJar, tCCR to invoke testCodeCoverageReport, and so on.
`,23)]))}const y=s(n,[["render",l]]);export{c as __pageData,y as default};
diff --git a/assets/guide_project-tutorial.md.CaWZTWm8.js b/assets/guide_project-tutorial.md.CaWZTWm8.js
new file mode 100644
index 0000000..aff0d69
--- /dev/null
+++ b/assets/guide_project-tutorial.md.CaWZTWm8.js
@@ -0,0 +1,17 @@
+import{_ as a,c as i,a2 as e,o as n}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Aya Package","description":"","frontmatter":{},"headers":[],"relativePath":"guide/project-tutorial.md","filePath":"guide/project-tutorial.md","lastUpdated":1717298851000}'),t={name:"guide/project-tutorial.md"};function p(l,s,o,h,r,k){return n(),i("div",null,s[0]||(s[0]=[e(`
An Aya project consists of a directory with a aya.json file (project metadata) and a src directory for source code. Here's a sample aya.json:
json
{
+ "ayaVersion": "0.31",
+ // ^ The version of Aya you are using -- for compatibility checks
+ "name": "<project name>",
+ "version": "<project version>",
+ "group": "<project group>",
+ // ^ The group is used to distinguish different projects with the same modules
+
+ "dependency": {
+ "<name of dependency>": {
+ "file": "<directory to your dependency>"
+ },
+ // We plan to support other sources of dependencies,
+ // but we do not have money to
+ // host a package repository for now.
+ }
+}
To build a project, run aya --make <parent dir of aya.json> (incremental). For force-rebuilding, replace --make with --remake. For jar users, run java --enable-preview -jar cli-fatjar.jar --make <parent dir of aya.json>.
`,4)]))}const E=a(t,[["render",p]]);export{c as __pageData,E as default};
diff --git a/assets/guide_project-tutorial.md.CaWZTWm8.lean.js b/assets/guide_project-tutorial.md.CaWZTWm8.lean.js
new file mode 100644
index 0000000..aff0d69
--- /dev/null
+++ b/assets/guide_project-tutorial.md.CaWZTWm8.lean.js
@@ -0,0 +1,17 @@
+import{_ as a,c as i,a2 as e,o as n}from"./chunks/framework.BnE-uSbk.js";const c=JSON.parse('{"title":"Aya Package","description":"","frontmatter":{},"headers":[],"relativePath":"guide/project-tutorial.md","filePath":"guide/project-tutorial.md","lastUpdated":1717298851000}'),t={name:"guide/project-tutorial.md"};function p(l,s,o,h,r,k){return n(),i("div",null,s[0]||(s[0]=[e(`
An Aya project consists of a directory with a aya.json file (project metadata) and a src directory for source code. Here's a sample aya.json:
json
{
+ "ayaVersion": "0.31",
+ // ^ The version of Aya you are using -- for compatibility checks
+ "name": "<project name>",
+ "version": "<project version>",
+ "group": "<project group>",
+ // ^ The group is used to distinguish different projects with the same modules
+
+ "dependency": {
+ "<name of dependency>": {
+ "file": "<directory to your dependency>"
+ },
+ // We plan to support other sources of dependencies,
+ // but we do not have money to
+ // host a package repository for now.
+ }
+}
To build a project, run aya --make <parent dir of aya.json> (incremental). For force-rebuilding, replace --make with --remake. For jar users, run java --enable-preview -jar cli-fatjar.jar --make <parent dir of aya.json>.
`,4)]))}const E=a(t,[["render",p]]);export{c as __pageData,E as default};
diff --git a/assets/guide_prover-tutorial.md.C3VZY-zt.js b/assets/guide_prover-tutorial.md.C3VZY-zt.js
new file mode 100644
index 0000000..e6998f4
--- /dev/null
+++ b/assets/guide_prover-tutorial.md.C3VZY-zt.js
@@ -0,0 +1,98 @@
+import{_ as g,c as w,j as a,a as s,a2 as v,o as I}from"./chunks/framework.BnE-uSbk.js";const T={mounted(){const y=new Map;function p(c){const e=c.querySelectorAll("a[href]");for(const r of e){const n=r.href,i=y.get(n)??new Set;i.add(r),y.set(n,i)}for(const r of e)r.onmouseover=function(){for(const n of y.get(this.href))n.classList.add("hover-highlight")},r.onmouseout=function(){for(const n of y.get(this.href))n.classList.remove("hover-highlight")}}function d(c){return decodeURIComponent(atob(c).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const x=(c=>{const e={};return(...r)=>{const n=JSON.stringify(r);return e[n]=e[n]||c(...r)}})(d);class u{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(r=>r!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let r=this.list.find(n=>n.userCreatedFrom===e);this.dismissIfNotUsed(r)}createHoverFor(e,r,n){let i=this.list.find(o=>o.userCreatedFrom===e);if(i&&i.userClicked)return i;let M=[];const A=this.list.filter(o=>{if(this.allowAutoDismissal(o))return M.push(o),!1;const l=o.userCreatedFrom,f=e;let h=f;for(;h;){if(h===l)return!0;h=h.parentElement}for(h=l;h;){if(h===f)return!0;h=h.parentElement}return!1});M.forEach(o=>this.dismiss(o));let t=document.createElement("div");t.userCreatedFrom=e,t.innerHTML="×"+x(r),t.classList.add("AyaTooltipPopup"),p(t);let b=this;if(t.handleEvent=function(o){if(o.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let l=this.children[0];if(!l)return;let f=this;l.style.visibility="visible",l.addEventListener("click",h=>b.dismiss(f))}o.type==="mouseover"&&(this.userIsThinking=!0),o.type==="mouseout"&&(this.userIsThinking=!1,b.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),n.appendChild(t),t.style.left=`${e.offsetLeft}px`,A.length===0){const o=e.getBoundingClientRect(),l=t.getBoundingClientRect();o.bottom+l.height+30>window.innerHeight?t.style.top=`calc(${e.offsetTop-l.height+8}px - 3em)`:t.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const o=Math.max(...A.map(l=>l.offsetTop+l.offsetHeight));t.style.top=`${o+8}px`}return this.list.push(t),t}}let m=new u;function V(c){return function(){let e=this;const r=e.getAttribute("data-tooltip-text");r&&(c?m.createHoverFor(e,r,document.body):m.fireAutoDismissalFor(e))}}p(document);{let c=document.getElementsByClassName("aya-tooltip");for(let e=0;e {??}")]),s(`
+`)],-1),a("p",null,"There is no way to prove it in Martin-Löf type theory or Calculus of Constructions. However, you are very smart and realized you can instead show the following:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-Goal27",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Goal27"},[a("span",{class:"Fn"},"Goal'")]),s(" ("),a("a",{id:"v2100440237",class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Bool"},[a("span",{class:"Data"},"Bool")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-id"},[a("span",{class:"Fn"},"id")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-not"},[a("span",{class:"Fn"},"not")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-not"},[a("span",{class:"Fn"},"not")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(")")]),s(`
+`)],-1),v('
This is pretty much the same theorem!
Now, suppose we need to show a propositional equality between two records. This means we have to show they're memberwise equal. One record has a member \\p0 ⇒ not(notp0), and the other has id. This time, you cannot cheat by changing the goal type. You post the question on some mailing list and people are telling you that the alternative version of the theorem you have shown does not imply the original, unless "function extensionality" is a theorem in your type theory.
To have function extensionality as a theorem, you came across two distinct type theories: observational type theory and cubical type theory. Aya chose the latter.
Aya has a "cubical" equality type that is not inductively defined. An equality a = b for a, b : A is really just a function I → A (as we can see from the proof construction, for f = g we prove it by a lambda abstraction) where:
I is a special type that has two closed instances 0 and 1, and we think of there being a propositional equality between 0 and 1, and there is no pattern matching operation that distinguishes them. So, every function that maps out of I must preserve this judgmental equality.
For f : I -> A, the corresponding equality type is f 0 = f 1. Hypothetically, let f be the identity function, and we get a propositional equality between 0 and 1, but for technical reasons we don't talk about equality between 0 and 1 directly.
By this definition, we can "prove" reflexivity by creating a constant function:
For f = fn i => a, we need to verify if f 0 equals the left-hand side of the equality and f 1 equals the right-hand side, which are both true.
And to show that f = g, it suffices to construct a function q : I -> (A -> B) such that q 0 = f and q 1 = g. This is true for the proof above:
(fn i a => p a i) 0 β-reduce
+= fn a => p a 0 p a : f a = g a
+= fn a => f a η-reduce
+= f
We may also prove the action-on-path theorem, commonly known as cong, but renamed to pmap to avoid a potential future naming clash:
`,4),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-pmap",class:"aya-hover","aya-hover-text":"f a = f b",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("a",{id:"v1176164144",class:"aya-hover","aya-hover-text":"A → B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") {"),a("a",{id:"v1323434987",class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v442125849",class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v1624972302",class:"aya-hover","aya-hover-text":"a = b",href:"#v1624972302"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(`
+ ⇒ `),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1201466784",href:"#v1201466784"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1624972302"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1201466784"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,"Checking the above definition is left as an exercise.",-1),a("p",null,[s("However, we cannot yet define transitivity/symmetry of equality because we do not have the traditional elimination rule of the equality type -- the "),a("code",null,"J"),s(" rule. This will need some advanced proving techniques that are beyond the scope of this simple tutorial, so I'll skim them.")],-1),a("p",null,"We may define the type-safe coercion using it, and this will help us prove the two lemmas about equality:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-cast",class:"aya-hover","aya-hover-text":"A → B",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("a",{id:"v1365767549",class:"aya-hover","aya-hover-text":"A = B",href:"#v1365767549"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 1",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(" ⇒ "),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#Mian-coe"},[a("span",{class:"Primitive"},"coe")]),s(" 0 1 ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1217207511",href:"#v1217207511"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1365767549"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1217207511"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,[s("Then, from "),a("code",null,"p : a = b"),s(" we construct the equivalence "),a("code",null,"(a = a) = (b = a)"),s(" and coerce along this equivalence:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-pinv",class:"aya-hover","aya-hover-text":"b = a",href:"#Mian-pinv"},[a("span",{class:"Fn"},"pinv")]),s(" {"),a("a",{id:"v1042306518",class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v1342346098",class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v1358343316",class:"aya-hover","aya-hover-text":"a = b",href:"#v1358343316"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"b = a",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("span",{class:"Keyword"},"\\"),a("a",{id:"v1759250827",href:"#v1759250827"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1358343316"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1759250827"},[a("span",{class:"LocalVar"},"i")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"a = a",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")])]),s(`
+`)],-1),a("p",null,[s("From "),a("code",null,"q : b = c"),s(" we construct the equivalence "),a("code",null,"(a = b) = (a = c)"),s(" and coerce along this equivalence:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-concat",class:"aya-hover","aya-hover-text":"a = c",href:"#Mian-concat"},[a("span",{class:"Fn"},"concat")]),s(" {"),a("a",{id:"v2107577743",class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v1173346575",class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{id:"v1267149311",class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v52514534",class:"aya-hover","aya-hover-text":"a = b",href:"#v52514534"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(") ("),a("a",{id:"v1242027525",class:"aya-hover","aya-hover-text":"b = c",href:"#v1242027525"},[a("span",{class:"LocalVar"},"q")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(` ⇒
+ `),a("a",{class:"aya-hover","aya-hover-text":"a = c",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("span",{class:"Keyword"},"\\"),a("a",{id:"v951741667",href:"#v951741667"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1242027525"},[a("span",{class:"LocalVar"},"q")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v951741667"},[a("span",{class:"LocalVar"},"i")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"a = b",href:"#v52514534"},[a("span",{class:"LocalVar"},"p")])]),s(`
+`)],-1),a("p",null,"Note that at this point you can already do a bunch of familiar proofs about some simple types such as natural numbers or sized vectors. These are left as exercises, and you are encouraged to try yourself if you are not very sure about how it feels to prove things in Aya.",-1),a("h2",{id:"overlapping-and-order-independent-pattern-matching",tabindex:"-1"},[s("Overlapping and Order-independent Pattern Matching "),a("a",{class:"header-anchor",href:"#overlapping-and-order-independent-pattern-matching","aria-label":'Permalink to "Overlapping and Order-independent Pattern Matching"'},"")],-1),a("p",null,[s("Remember the "),a("code",null,"+-comm"),s(" proof that you need two lemmas? It is standard to define "),a("code",null,"+"),s(" in the following way:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infix"),s(),a("a",{id:"Mian-3aNoExport-2b",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v2144838275",class:"aya-hover","aya-hover-text":"Nat",href:"#v2144838275"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2144838275"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v1423983012",class:"aya-hover","aya-hover-text":"Nat",href:"#v1423983012"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v746074699",class:"aya-hover","aya-hover-text":"Nat",href:"#v746074699"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1423983012"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v746074699"},[a("span",{class:"LocalVar"},"n")]),s(")")]),s(`
+`)],-1),a("p",null,[s("And then you prove that "),a("code",null,"a + 0 = a"),s(" and "),a("code",null,"a + suc b = suc (a + b)"),s(". It is tempting to have "),a("code",null,"| n, 0 => n"),s(" as a computation rule as well, but this is incompatible with the usual semantics of pattern matching, which is compiled to elimination principles during type checking. However, you "),a("em",null,"can"),s(" do that in Aya. You may also add the other lemma as well.")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"overlap"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infix"),s(),a("a",{id:"Mian-2b",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v2112233878",class:"aya-hover","aya-hover-text":"Nat",href:"#v2112233878"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2112233878"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{id:"v372469954",class:"aya-hover","aya-hover-text":"Nat",href:"#v372469954"},[a("span",{class:"LocalVar"},"n")]),s(", 0 ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v372469954"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v1371495133",class:"aya-hover","aya-hover-text":"Nat",href:"#v1371495133"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v2030411960",class:"aya-hover","aya-hover-text":"Nat",href:"#v2030411960"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1371495133"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2030411960"},[a("span",{class:"LocalVar"},"n")]),s(`)
+| `),a("a",{id:"v899929247",class:"aya-hover","aya-hover-text":"Nat",href:"#v899929247"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v949684105",class:"aya-hover","aya-hover-text":"Nat",href:"#v949684105"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v899929247"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v949684105"},[a("span",{class:"LocalVar"},"n")]),s(`)
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")])]),s(`
+`)],-1),a("p",null,[s("This makes all of them definitional equality. So, "),a("code",{class:"Aya"},[a("a",{href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")])]),s(" can be simplified to just one pattern matching:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b-comm",class:"aya-hover","aya-hover-text":"(a + b) = (b + a)",href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")]),s(" ("),a("a",{id:"v412111214",class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v362827515",class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(`
+| 0 ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"b = b",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" _ ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"suc (_ + b) = suc (b + _)",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat → Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"(_ + b) = (b + _)",href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3Y0MTI5MjUzMDgiPjxzcGFuIGNsYXNzPSJMb2NhbFZhciI+Xzwvc3Bhbj48L2E+PC9jb2RlPgo8L3ByZT4K"},"_"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3YyMDc5NTY1MjcyIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPmI8L3NwYW4+PC9hPjwvY29kZT4KPC9wcmU+Cg=="},"_"),s(")")]),s(`
+`)],-1),a("p",null,[s("Note that we are using the "),a("code",null,"elim"),s(" keyword, which describes the variables that the function body is pattern matching on.")],-1),a("h2",{id:"heterogeneous-equality",tabindex:"-1"},[s("Heterogeneous equality "),a("a",{class:"header-anchor",href:"#heterogeneous-equality","aria-label":'Permalink to "Heterogeneous equality"'},"")],-1),a("p",null,"When working with indexed families, you may want to have heterogeneous equality to avoid having mysterious coercions. For example, consider the associativity of sized vector appends. We first need to define sized vectors and the append operation:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v1029472813",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{id:"v282265585",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{id:"v1304117943",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+`),a("span",{class:"Comment"},"// Definitions"),s(`
+`),a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Vec",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{id:"v596706728",class:"aya-hover","aya-hover-text":"Nat",href:"#v596706728"},[a("span",{class:"LocalVar"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") ("),a("a",{id:"v1070501849",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1070501849"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| 0, `),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v1620823990",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1620823990"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("a",{id:"Mian-Vec-nil",class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+bjwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v1298146757",class:"aya-hover","aya-hover-text":"Nat",href:"#v1298146757"},[a("span",{class:"LocalVar"},"n")])])]),s(", "),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v2133344792",class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-Vec-3a3c",class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1298146757"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")]),s(`)
+`),a("span",{class:"Keyword"},"overlap"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-2b2b",class:"aya-hover","aya-hover-text":"Vec (n + m) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(", "),a("a",{id:"v258112787",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v258112787"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v258112787"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v841262455",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v841262455"},[a("span",{class:"LocalVar"},"ys")]),s(", "),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v841262455"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v1044705957",class:"aya-hover","aya-hover-text":"A",href:"#v1044705957"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{id:"v693958407",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v693958407"},[a("span",{class:"LocalVar"},"xs")]),s(", "),a("a",{id:"v288379405",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v288379405"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1044705957"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc (?n A x xs ys n m)) (?A A x xs ys n m)",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v693958407"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n A x xs ys n m + ?m A x xs ys n m) (?A A x xs ys n m)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v288379405"},[a("span",{class:"LocalVar"},"ys")]),s(`
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")])]),s(`
+`)],-1),v(`
It is tempting to use the below definition:
overlap def ++-assoc (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
+ : (xs ++ ys) ++ zs = xs ++ (ys ++ zs) elim xs
+| nil => refl
+| x :< xs => pmap (x :<) (++-assoc xs ys zs)
They are not the same! Fortunately, we can prove that they are propositionally equal. We need to show that natural number addition is associative, which is the key lemma of this propositional equality:
`,5),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b-assoc",class:"aya-hover","aya-hover-text":"((a + b) + c) = (a + (b + c))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(" {"),a("a",{id:"v1720891078",class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v483797427",class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{id:"v1486726131",class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s("} : ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(") "),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(`
+| 0 ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"(b + c) = (b + c)",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" _ ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"suc ((_ + b) + c) = suc (_ + (b + c))",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat → Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"((_ + b) + c) = (_ + (b + c))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")])]),s(`
+`)],-1),v('
Now we can work on the proof of ++-assoc. Here's a lame definition that is well-typed in pre-cubical type theory, and is also hard to prove -- we cast one side of the equation to be other side. So instead of:
xs ++ (ys ++ zs) = (xs ++ ys) ++ zs
We show:
f (xs ++ (ys ++ zs)) = (xs ++ ys) ++ zs
Where f is a function that changes the type of the vector, implemented using cast. The definition looks like this:
',5),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-3aNoExport-2b2b-assoc-ty",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3aNoExport-2b2b-assoc-ty"},[a("span",{class:"Fn"},"++-assoc-ty")]),s(" ("),a("a",{id:"v2139788441",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1564698139",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v304715920",class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`)
+ ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"Vec (n + (m + o)) A",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A = Vec (n + (m + o)) A",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v762074108",href:"#v762074108"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v762074108"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"((n + m) + o) = (n + (m + o))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(") (("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(")")]),s(`
+`)],-1),v('
It is harder to prove because in the induction step, one need to show that cast(pmap (\\p0 ⇒ Vecp0A) +-assoc) is equivalent to the identity function in order to use the induction hypothesis. For the record, here's the proof:
',1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-castRefl",class:"aya-hover","aya-hover-text":"cast refl a = a",href:"#Mian-castRefl"},[a("span",{class:"Fn"},"castRefl")]),s(" ("),a("a",{id:"v1801942731",class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"A = A",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v636782475",href:"#v636782475"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#Mian-coe"},[a("span",{class:"Primitive"},"coe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v636782475"},[a("span",{class:"LocalVar"},"i")]),s(" 1 ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1312963234",href:"#v1312963234"},[a("span",{class:"LocalVar"},"j")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")])]),s(`
+`)],-1),a("p",null,"But still, with this lemma it is still hard. Cubical provides a pleasant way of working with heterogeneous equality:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-Path27",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path27"},[a("span",{class:"Fn"},"Path'")]),s(" ("),a("a",{id:"v1513608173",class:"aya-hover","aya-hover-text":"I → Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"ISet",href:"#Mian-I"},[a("span",{class:"Primitive"},"I")]),s(" → "),a("span",{class:"Keyword"},"Type"),s(") ("),a("a",{id:"v652176954",class:"aya-hover","aya-hover-text":"A 0",href:"#v652176954"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" 0) ("),a("a",{id:"v1245065720",class:"aya-hover","aya-hover-text":"A 1",href:"#v1245065720"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" 1) ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path"},[a("span",{class:"Primitive"},"Path")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I → Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A 0",href:"#v652176954"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A 1",href:"#v1245065720"},[a("span",{class:"LocalVar"},"b")])]),s(`
+`)],-1),v("
So if we have X : A = B and a : A, b : B, then Path (\\i => X i) a b expresses the heterogeneous equality between a and b nicely.
We may then use the following type signature:
",2),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b2b-assoc-type",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-2b2b-assoc-type"},[a("span",{class:"Fn"},"++-assoc-type")]),s(" ("),a("a",{id:"v765242091",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1117871068",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1151704483",class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`)
+ ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path"},[a("span",{class:"Primitive"},"Path")]),s(" ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v2143139988",href:"#v2143139988"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v2143139988"},[a("span",{class:"LocalVar"},"i")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") (("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s("))")]),s(`
+`)],-1),a("p",null,"The proof is omitted (try yourself!).",-1),a("h2",{id:"quotient-inductive-types",tabindex:"-1"},[s("Quotient inductive types "),a("a",{class:"header-anchor",href:"#quotient-inductive-types","aria-label":'Permalink to "Quotient inductive types"'},"")],-1),a("p",null,"Quotient types are types that equates their instances in a non-trivial way. In Aya, they are defined using the following syntax:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Interval",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Interval"},[a("span",{class:"Data"},"Interval")]),s(`
+| `),a("a",{id:"Mian-Interval-left",class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(`
+| `),a("a",{id:"Mian-Interval-right",class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")]),s(`
+| `),a("a",{id:"Mian-Interval-line",class:"aya-hover","aya-hover-text":"left = right",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")])]),s(`
+`)],-1),v('
This is an uninteresting quotient type, that is basically Bool but saying its two values are equal, so it's really just a unit type, with its unique element being the equivalence class of left and right.
If you're familiar with a proof assistant with an intensional equality like Coq/Agda/Lean/etc., you might find this surprising because a unit type shall not have two distinct elements, and an equality shall not be stated between two distinct constructors. How does this work in Aya?
Actually, in these systems, the equality is defined inductively, and it only has one constructor -- refl. This is not how equality is defined in Aya, so we can cook some interesting equality proofs into it, which includes these equality-looking constructors.
The type of line will be translated into I → Interval together with the judgmental equality that line0 is left and line1 is right, basically a desugaring of the equality with additional features. This makes line a valid constructor in normal type theory: it takes some parameters and returns Interval.
These judgmental equalities need to be preserved by the elimination rule of Interval. Here is an example elimination:
Note that the term pmap Interval-elim line, which reduces to p, has type Interval-elim left = Interval-elim right, so we need to check if p 0 equals Interval-elim left, and p 1 equals Interval-elim right. This is a confluence check that ensures the elimination is well-defined.
What's interesting about this type, is that its elimination implies function extensionality:
",2),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"private"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-lemma",class:"aya-hover","aya-hover-text":"B",href:"#Mian-lemma"},[a("span",{class:"Fn"},"lemma")]),s(`
+ (`),a("a",{id:"v1872973138",class:"aya-hover","aya-hover-text":"A → B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{id:"v1465346452",class:"aya-hover","aya-hover-text":"A → B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") ("),a("a",{id:"v302366050",class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v302366050"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("span",{class:"Keyword"},"∀"),s(),a("a",{id:"v813823788",class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(`)
+ (`),a("a",{id:"v2129821055",class:"aya-hover","aya-hover-text":"Interval",href:"#v2129821055"},[a("span",{class:"LocalVar"},"i")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Interval"},[a("span",{class:"Data"},"Interval")]),s(") ("),a("a",{id:"v1225568095",class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v2129821055"},[a("span",{class:"LocalVar"},"i")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"left = right",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(),a("a",{id:"v451460284",class:"aya-hover","aya-hover-text":"I",href:"#v451460284"},[a("span",{class:"LocalVar"},"j")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v302366050"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v451460284"},[a("span",{class:"LocalVar"},"j")]),s(`
+
+`),a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-3aNoExport-funExt27",class:"aya-hover","aya-hover-text":"f = g",href:"#Mian-3aNoExport-funExt27"},[a("span",{class:"Fn"},"funExt'")]),s(" ("),a("a",{id:"v1558103808",class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{id:"v1828873985",class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") ("),a("a",{id:"v892965953",class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v892965953"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("span",{class:"Keyword"},"∀"),s(),a("a",{id:"v826865256",class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(` ⇒
+ `),a("a",{class:"aya-hover","aya-hover-text":"lemma f g p left = lemma f g p right",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Interval → A → B",href:"#Mian-lemma"},[a("span",{class:"Fn"},"lemma")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v892965953"},[a("span",{class:"LocalVar"},"p")]),s(") ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1845517769",href:"#v1845517769"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1845517769"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,[s("Note that even though we are using equation combinators like "),a("code",{class:"Aya"},[a("a",{href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")])]),s(" which are implemented using path application and abstraction, it is not considered cheating because these are already theorems in MLTT anyway.")],-1),a("p",null,"We can define other interesting quotients such as a symmetric integer:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Int",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(`
+| `),a("a",{id:"Mian-Int-pos",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" | "),a("a",{id:"Mian-Int-neg",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| `),a("a",{id:"Mian-Int-zro",class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(" 0 "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" 0")]),s(`
+`)],-1),a("p",null,[s("Some operations on "),a("code",{class:"Aya"},[a("a",{href:"#Mian-Int"},[a("span",{class:"Data"},"Int")])]),s(":")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-succ",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-succ"},[a("span",{class:"Fn"},"succ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{id:"v380812044",class:"aya-hover","aya-hover-text":"Nat",href:"#v380812044"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v380812044"},[a("span",{class:"LocalVar"},"n")]),s(`)
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" 0 ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(` 1
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v846918683",class:"aya-hover","aya-hover-text":"Nat",href:"#v846918683"},[a("span",{class:"LocalVar"},"n")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v846918683"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(),a("a",{id:"v1823923917",class:"aya-hover","aya-hover-text":"I",href:"#v1823923917"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(` 1
+
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-abs",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-abs"},[a("span",{class:"Fn"},"abs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{id:"v1789268516",class:"aya-hover","aya-hover-text":"Nat",href:"#v1789268516"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1789268516"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{id:"v817686795",class:"aya-hover","aya-hover-text":"Nat",href:"#v817686795"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v817686795"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(" _ ⇒ 0")]),s(`
+`)],-1),v('
The succ operator has the first three clauses straightforward, and the last one is a proof of succ(neg0) equals succ(pos0), as we should preserve the judgmental equality in the type of zro. We need to do the same for abs.
',1)]))}const z=g(T,[["render",N]]);export{B as __pageData,z as default};
diff --git a/assets/guide_prover-tutorial.md.C3VZY-zt.lean.js b/assets/guide_prover-tutorial.md.C3VZY-zt.lean.js
new file mode 100644
index 0000000..e6998f4
--- /dev/null
+++ b/assets/guide_prover-tutorial.md.C3VZY-zt.lean.js
@@ -0,0 +1,98 @@
+import{_ as g,c as w,j as a,a as s,a2 as v,o as I}from"./chunks/framework.BnE-uSbk.js";const T={mounted(){const y=new Map;function p(c){const e=c.querySelectorAll("a[href]");for(const r of e){const n=r.href,i=y.get(n)??new Set;i.add(r),y.set(n,i)}for(const r of e)r.onmouseover=function(){for(const n of y.get(this.href))n.classList.add("hover-highlight")},r.onmouseout=function(){for(const n of y.get(this.href))n.classList.remove("hover-highlight")}}function d(c){return decodeURIComponent(atob(c).split("").map(function(e){return"%"+("00"+e.charCodeAt(0).toString(16)).slice(-2)}).join(""))}const x=(c=>{const e={};return(...r)=>{const n=JSON.stringify(r);return e[n]=e[n]||c(...r)}})(d);class u{constructor(){this.list=[]}dismiss(e){e&&(e.remove(),this.list=this.list.filter(r=>r!==e))}dismissIfNotUsed(e){e&&(e.markedForDismissal=!0,setTimeout(()=>{!e.userIsThinking&&this.allowAutoDismissal(e)&&this.dismiss(e)},1e3))}allowAutoDismissal(e){return e.markedForDismissal&&!e.userClicked}fireAutoDismissalFor(e){let r=this.list.find(n=>n.userCreatedFrom===e);this.dismissIfNotUsed(r)}createHoverFor(e,r,n){let i=this.list.find(o=>o.userCreatedFrom===e);if(i&&i.userClicked)return i;let M=[];const A=this.list.filter(o=>{if(this.allowAutoDismissal(o))return M.push(o),!1;const l=o.userCreatedFrom,f=e;let h=f;for(;h;){if(h===l)return!0;h=h.parentElement}for(h=l;h;){if(h===f)return!0;h=h.parentElement}return!1});M.forEach(o=>this.dismiss(o));let t=document.createElement("div");t.userCreatedFrom=e,t.innerHTML="×"+x(r),t.classList.add("AyaTooltipPopup"),p(t);let b=this;if(t.handleEvent=function(o){if(o.type==="click"){this.userClicked=!0,this.markedForDismissal=!1;let l=this.children[0];if(!l)return;let f=this;l.style.visibility="visible",l.addEventListener("click",h=>b.dismiss(f))}o.type==="mouseover"&&(this.userIsThinking=!0),o.type==="mouseout"&&(this.userIsThinking=!1,b.dismissIfNotUsed(this))},t.addEventListener("click",t),t.addEventListener("mouseover",t),t.addEventListener("mouseout",t),n.appendChild(t),t.style.left=`${e.offsetLeft}px`,A.length===0){const o=e.getBoundingClientRect(),l=t.getBoundingClientRect();o.bottom+l.height+30>window.innerHeight?t.style.top=`calc(${e.offsetTop-l.height+8}px - 3em)`:t.style.top=`${e.offsetTop+e.offsetHeight+8}px`}else{const o=Math.max(...A.map(l=>l.offsetTop+l.offsetHeight));t.style.top=`${o+8}px`}return this.list.push(t),t}}let m=new u;function V(c){return function(){let e=this;const r=e.getAttribute("data-tooltip-text");r&&(c?m.createHoverFor(e,r,document.body):m.fireAutoDismissalFor(e))}}p(document);{let c=document.getElementsByClassName("aya-tooltip");for(let e=0;e {??}")]),s(`
+`)],-1),a("p",null,"There is no way to prove it in Martin-Löf type theory or Calculus of Constructions. However, you are very smart and realized you can instead show the following:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-Goal27",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Goal27"},[a("span",{class:"Fn"},"Goal'")]),s(" ("),a("a",{id:"v2100440237",class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Bool"},[a("span",{class:"Data"},"Bool")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-id"},[a("span",{class:"Fn"},"id")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-not"},[a("span",{class:"Fn"},"not")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#Mian-not"},[a("span",{class:"Fn"},"not")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Bool",href:"#v2100440237"},[a("span",{class:"LocalVar"},"x")]),s(")")]),s(`
+`)],-1),v('
This is pretty much the same theorem!
Now, suppose we need to show a propositional equality between two records. This means we have to show they're memberwise equal. One record has a member \\p0 ⇒ not(notp0), and the other has id. This time, you cannot cheat by changing the goal type. You post the question on some mailing list and people are telling you that the alternative version of the theorem you have shown does not imply the original, unless "function extensionality" is a theorem in your type theory.
To have function extensionality as a theorem, you came across two distinct type theories: observational type theory and cubical type theory. Aya chose the latter.
Aya has a "cubical" equality type that is not inductively defined. An equality a = b for a, b : A is really just a function I → A (as we can see from the proof construction, for f = g we prove it by a lambda abstraction) where:
I is a special type that has two closed instances 0 and 1, and we think of there being a propositional equality between 0 and 1, and there is no pattern matching operation that distinguishes them. So, every function that maps out of I must preserve this judgmental equality.
For f : I -> A, the corresponding equality type is f 0 = f 1. Hypothetically, let f be the identity function, and we get a propositional equality between 0 and 1, but for technical reasons we don't talk about equality between 0 and 1 directly.
By this definition, we can "prove" reflexivity by creating a constant function:
For f = fn i => a, we need to verify if f 0 equals the left-hand side of the equality and f 1 equals the right-hand side, which are both true.
And to show that f = g, it suffices to construct a function q : I -> (A -> B) such that q 0 = f and q 1 = g. This is true for the proof above:
(fn i a => p a i) 0 β-reduce
+= fn a => p a 0 p a : f a = g a
+= fn a => f a η-reduce
+= f
We may also prove the action-on-path theorem, commonly known as cong, but renamed to pmap to avoid a potential future naming clash:
`,4),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-pmap",class:"aya-hover","aya-hover-text":"f a = f b",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("a",{id:"v1176164144",class:"aya-hover","aya-hover-text":"A → B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") {"),a("a",{id:"v1323434987",class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v442125849",class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v1624972302",class:"aya-hover","aya-hover-text":"a = b",href:"#v1624972302"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1323434987"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v442125849"},[a("span",{class:"LocalVar"},"b")]),s(`
+ ⇒ `),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1201466784",href:"#v1201466784"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1176164144"},[a("span",{class:"LocalVar"},"f")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1624972302"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1201466784"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,"Checking the above definition is left as an exercise.",-1),a("p",null,[s("However, we cannot yet define transitivity/symmetry of equality because we do not have the traditional elimination rule of the equality type -- the "),a("code",null,"J"),s(" rule. This will need some advanced proving techniques that are beyond the scope of this simple tutorial, so I'll skim them.")],-1),a("p",null,"We may define the type-safe coercion using it, and this will help us prove the two lemmas about equality:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-cast",class:"aya-hover","aya-hover-text":"A → B",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("a",{id:"v1365767549",class:"aya-hover","aya-hover-text":"A = B",href:"#v1365767549"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 1",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(" ⇒ "),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#Mian-coe"},[a("span",{class:"Primitive"},"coe")]),s(" 0 1 ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1217207511",href:"#v1217207511"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1365767549"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1217207511"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,[s("Then, from "),a("code",null,"p : a = b"),s(" we construct the equivalence "),a("code",null,"(a = a) = (b = a)"),s(" and coerce along this equivalence:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-pinv",class:"aya-hover","aya-hover-text":"b = a",href:"#Mian-pinv"},[a("span",{class:"Fn"},"pinv")]),s(" {"),a("a",{id:"v1042306518",class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v1342346098",class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v1358343316",class:"aya-hover","aya-hover-text":"a = b",href:"#v1358343316"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1342346098"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"b = a",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("span",{class:"Keyword"},"\\"),a("a",{id:"v1759250827",href:"#v1759250827"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1358343316"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1759250827"},[a("span",{class:"LocalVar"},"i")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1042306518"},[a("span",{class:"LocalVar"},"a")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"a = a",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")])]),s(`
+`)],-1),a("p",null,[s("From "),a("code",null,"q : b = c"),s(" we construct the equivalence "),a("code",null,"(a = b) = (a = c)"),s(" and coerce along this equivalence:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-concat",class:"aya-hover","aya-hover-text":"a = c",href:"#Mian-concat"},[a("span",{class:"Fn"},"concat")]),s(" {"),a("a",{id:"v2107577743",class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v1173346575",class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{id:"v1267149311",class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s("} ("),a("a",{id:"v52514534",class:"aya-hover","aya-hover-text":"a = b",href:"#v52514534"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(") ("),a("a",{id:"v1242027525",class:"aya-hover","aya-hover-text":"b = c",href:"#v1242027525"},[a("span",{class:"LocalVar"},"q")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1173346575"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1267149311"},[a("span",{class:"LocalVar"},"c")]),s(` ⇒
+ `),a("a",{class:"aya-hover","aya-hover-text":"a = c",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("span",{class:"Keyword"},"\\"),a("a",{id:"v951741667",href:"#v951741667"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v2107577743"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1242027525"},[a("span",{class:"LocalVar"},"q")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v951741667"},[a("span",{class:"LocalVar"},"i")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"a = b",href:"#v52514534"},[a("span",{class:"LocalVar"},"p")])]),s(`
+`)],-1),a("p",null,"Note that at this point you can already do a bunch of familiar proofs about some simple types such as natural numbers or sized vectors. These are left as exercises, and you are encouraged to try yourself if you are not very sure about how it feels to prove things in Aya.",-1),a("h2",{id:"overlapping-and-order-independent-pattern-matching",tabindex:"-1"},[s("Overlapping and Order-independent Pattern Matching "),a("a",{class:"header-anchor",href:"#overlapping-and-order-independent-pattern-matching","aria-label":'Permalink to "Overlapping and Order-independent Pattern Matching"'},"")],-1),a("p",null,[s("Remember the "),a("code",null,"+-comm"),s(" proof that you need two lemmas? It is standard to define "),a("code",null,"+"),s(" in the following way:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infix"),s(),a("a",{id:"Mian-3aNoExport-2b",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v2144838275",class:"aya-hover","aya-hover-text":"Nat",href:"#v2144838275"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2144838275"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v1423983012",class:"aya-hover","aya-hover-text":"Nat",href:"#v1423983012"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v746074699",class:"aya-hover","aya-hover-text":"Nat",href:"#v746074699"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1423983012"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-3aNoExport-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v746074699"},[a("span",{class:"LocalVar"},"n")]),s(")")]),s(`
+`)],-1),a("p",null,[s("And then you prove that "),a("code",null,"a + 0 = a"),s(" and "),a("code",null,"a + suc b = suc (a + b)"),s(". It is tempting to have "),a("code",null,"| n, 0 => n"),s(" as a computation rule as well, but this is incompatible with the usual semantics of pattern matching, which is compiled to elimination principles during type checking. However, you "),a("em",null,"can"),s(" do that in Aya. You may also add the other lemma as well.")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"overlap"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infix"),s(),a("a",{id:"Mian-2b",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| 0, `),a("a",{id:"v2112233878",class:"aya-hover","aya-hover-text":"Nat",href:"#v2112233878"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2112233878"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{id:"v372469954",class:"aya-hover","aya-hover-text":"Nat",href:"#v372469954"},[a("span",{class:"LocalVar"},"n")]),s(", 0 ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v372469954"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v1371495133",class:"aya-hover","aya-hover-text":"Nat",href:"#v1371495133"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{id:"v2030411960",class:"aya-hover","aya-hover-text":"Nat",href:"#v2030411960"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1371495133"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v2030411960"},[a("span",{class:"LocalVar"},"n")]),s(`)
+| `),a("a",{id:"v899929247",class:"aya-hover","aya-hover-text":"Nat",href:"#v899929247"},[a("span",{class:"LocalVar"},"m")]),s(", "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v949684105",class:"aya-hover","aya-hover-text":"Nat",href:"#v949684105"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v899929247"},[a("span",{class:"LocalVar"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v949684105"},[a("span",{class:"LocalVar"},"n")]),s(`)
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")])]),s(`
+`)],-1),a("p",null,[s("This makes all of them definitional equality. So, "),a("code",{class:"Aya"},[a("a",{href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")])]),s(" can be simplified to just one pattern matching:")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b-comm",class:"aya-hover","aya-hover-text":"(a + b) = (b + a)",href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")]),s(" ("),a("a",{id:"v412111214",class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v362827515",class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v362827515"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v412111214"},[a("span",{class:"LocalVar"},"a")]),s(`
+| 0 ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"b = b",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" _ ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"suc (_ + b) = suc (b + _)",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat → Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"(_ + b) = (b + _)",href:"#Mian-2b-comm"},[a("span",{class:"Fn"},"+-comm")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3Y0MTI5MjUzMDgiPjxzcGFuIGNsYXNzPSJMb2NhbFZhciI+Xzwvc3Bhbj48L2E+PC9jb2RlPgo8L3ByZT4K"},"_"),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+PGEgaHJlZj0iI3YyMDc5NTY1MjcyIj48c3BhbiBjbGFzcz0iTG9jYWxWYXIiPmI8L3NwYW4+PC9hPjwvY29kZT4KPC9wcmU+Cg=="},"_"),s(")")]),s(`
+`)],-1),a("p",null,[s("Note that we are using the "),a("code",null,"elim"),s(" keyword, which describes the variables that the function body is pattern matching on.")],-1),a("h2",{id:"heterogeneous-equality",tabindex:"-1"},[s("Heterogeneous equality "),a("a",{class:"header-anchor",href:"#heterogeneous-equality","aria-label":'Permalink to "Heterogeneous equality"'},"")],-1),a("p",null,"When working with indexed families, you may want to have heterogeneous equality to avoid having mysterious coercions. For example, consider the associativity of sized vector appends. We first need to define sized vectors and the append operation:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"variable"),s(),a("a",{id:"v1029472813",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{id:"v282265585",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{id:"v1304117943",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+`),a("span",{class:"Comment"},"// Definitions"),s(`
+`),a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Vec",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{id:"v596706728",class:"aya-hover","aya-hover-text":"Nat",href:"#v596706728"},[a("span",{class:"LocalVar"},"n")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(") ("),a("a",{id:"v1070501849",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1070501849"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("span",{class:"Keyword"},"Type"),s(`)
+| 0, `),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v1620823990",class:"aya-hover","aya-hover-text":"Type 0",href:"#v1620823990"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("a",{id:"Mian-Vec-nil",class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+bjwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v1298146757",class:"aya-hover","aya-hover-text":"Nat",href:"#v1298146757"},[a("span",{class:"LocalVar"},"n")])])]),s(", "),a("span",{class:"aya-tooltip","data-tooltip-text":"PHByZSBjbGFzcz0iQXlhIj4KPGNvZGU+V2FybmluZzogVGhlIG5hbWUgPGNvZGUgY2xhc3M9IkF5YSI+QTwvY29kZT4gc2hhZG93cyBhIHByZXZpb3VzIGxvY2FsIGRlZmluaXRpb24gZnJvbSBvdXRlciBzY29wZTwvY29kZT4KPC9wcmU+Cg=="},[a("span",{class:"Warning"},[a("a",{id:"v2133344792",class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")])])]),s(" ⇒ "),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-Vec-3a3c",class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1298146757"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v2133344792"},[a("span",{class:"LocalVar"},"A")]),s(`)
+`),a("span",{class:"Keyword"},"overlap"),s(),a("span",{class:"Keyword"},"def"),s(),a("span",{class:"Keyword"},"infixr"),s(),a("a",{id:"Mian-2b2b",class:"aya-hover","aya-hover-text":"Vec (n + m) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(", "),a("a",{id:"v258112787",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v258112787"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v258112787"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v841262455",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v841262455"},[a("span",{class:"LocalVar"},"ys")]),s(", "),a("a",{class:"aya-hover","aya-hover-text":"Vec 0 A",href:"#Mian-Vec-nil"},[a("span",{class:"Constructor"},"nil")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v841262455"},[a("span",{class:"LocalVar"},"ys")]),s(`
+| `),a("a",{id:"v1044705957",class:"aya-hover","aya-hover-text":"A",href:"#v1044705957"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{id:"v693958407",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v693958407"},[a("span",{class:"LocalVar"},"xs")]),s(", "),a("a",{id:"v288379405",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v288379405"},[a("span",{class:"LocalVar"},"ys")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1044705957"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc (?n A x xs ys n m)) (?A A x xs ys n m)",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v693958407"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n A x xs ys n m + ?m A x xs ys n m) (?A A x xs ys n m)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v288379405"},[a("span",{class:"LocalVar"},"ys")]),s(`
+`),a("span",{class:"Keyword"},"tighter"),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (suc n) A",href:"#Mian-Vec-3a3c"},[a("span",{class:"Constructor"},":<")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")])]),s(`
+`)],-1),v(`
It is tempting to use the below definition:
overlap def ++-assoc (xs : Vec n A) (ys : Vec m A) (zs : Vec o A)
+ : (xs ++ ys) ++ zs = xs ++ (ys ++ zs) elim xs
+| nil => refl
+| x :< xs => pmap (x :<) (++-assoc xs ys zs)
They are not the same! Fortunately, we can prove that they are propositionally equal. We need to show that natural number addition is associative, which is the key lemma of this propositional equality:
`,5),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b-assoc",class:"aya-hover","aya-hover-text":"((a + b) + c) = (a + (b + c))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(" {"),a("a",{id:"v1720891078",class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{id:"v483797427",class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{id:"v1486726131",class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s("} : ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v483797427"},[a("span",{class:"LocalVar"},"b")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b"},[a("span",{class:"Fn"},"+")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1486726131"},[a("span",{class:"LocalVar"},"c")]),s(") "),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v1720891078"},[a("span",{class:"LocalVar"},"a")]),s(`
+| 0 ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"(b + c) = (b + c)",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(" _ ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"suc ((_ + b) + c) = suc (_ + (b + c))",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat → Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"((_ + b) + c) = (_ + (b + c))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")])]),s(`
+`)],-1),v('
Now we can work on the proof of ++-assoc. Here's a lame definition that is well-typed in pre-cubical type theory, and is also hard to prove -- we cast one side of the equation to be other side. So instead of:
xs ++ (ys ++ zs) = (xs ++ ys) ++ zs
We show:
f (xs ++ (ys ++ zs)) = (xs ++ ys) ++ zs
Where f is a function that changes the type of the vector, implemented using cast. The definition looks like this:
',5),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-3aNoExport-2b2b-assoc-ty",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3aNoExport-2b2b-assoc-ty"},[a("span",{class:"Fn"},"++-assoc-ty")]),s(" ("),a("a",{id:"v2139788441",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1564698139",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v304715920",class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`)
+ ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"Vec (n + (m + o)) A",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A = Vec (n + (m + o)) A",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v762074108",href:"#v762074108"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v762074108"},[a("span",{class:"LocalVar"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"((n + m) + o) = (n + (m + o))",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(") (("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v2139788441"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1564698139"},[a("span",{class:"LocalVar"},"ys")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v304715920"},[a("span",{class:"LocalVar"},"zs")]),s(")")]),s(`
+`)],-1),v('
It is harder to prove because in the induction step, one need to show that cast(pmap (\\p0 ⇒ Vecp0A) +-assoc) is equivalent to the identity function in order to use the induction hypothesis. For the record, here's the proof:
',1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-castRefl",class:"aya-hover","aya-hover-text":"cast refl a = a",href:"#Mian-castRefl"},[a("span",{class:"Fn"},"castRefl")]),s(" ("),a("a",{id:"v1801942731",class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#Mian-cast"},[a("span",{class:"Fn"},"cast")]),s(),a("span",{class:"Keyword"},"↑"),s(),a("a",{class:"aya-hover","aya-hover-text":"A = A",href:"#Mian-refl"},[a("span",{class:"Fn"},"refl")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")]),s(" ⇒ "),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v636782475",href:"#v636782475"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#Mian-coe"},[a("span",{class:"Primitive"},"coe")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v636782475"},[a("span",{class:"LocalVar"},"i")]),s(" 1 ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1312963234",href:"#v1312963234"},[a("span",{class:"LocalVar"},"j")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1801942731"},[a("span",{class:"LocalVar"},"a")])]),s(`
+`)],-1),a("p",null,"But still, with this lemma it is still hard. Cubical provides a pleasant way of working with heterogeneous equality:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-Path27",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path27"},[a("span",{class:"Fn"},"Path'")]),s(" ("),a("a",{id:"v1513608173",class:"aya-hover","aya-hover-text":"I → Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"ISet",href:"#Mian-I"},[a("span",{class:"Primitive"},"I")]),s(" → "),a("span",{class:"Keyword"},"Type"),s(") ("),a("a",{id:"v652176954",class:"aya-hover","aya-hover-text":"A 0",href:"#v652176954"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" 0) ("),a("a",{id:"v1245065720",class:"aya-hover","aya-hover-text":"A 1",href:"#v1245065720"},[a("span",{class:"LocalVar"},"b")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(" 1) ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path"},[a("span",{class:"Primitive"},"Path")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I → Type 0",href:"#v1513608173"},[a("span",{class:"LocalVar"},"A")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A 0",href:"#v652176954"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A 1",href:"#v1245065720"},[a("span",{class:"LocalVar"},"b")])]),s(`
+`)],-1),v("
So if we have X : A = B and a : A, b : B, then Path (\\i => X i) a b expresses the heterogeneous equality between a and b nicely.
We may then use the following type signature:
",2),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-2b2b-assoc-type",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-2b2b-assoc-type"},[a("span",{class:"Fn"},"++-assoc-type")]),s(" ("),a("a",{id:"v765242091",class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1029472813"},[a("span",{class:"Generalized"},"n")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1117871068",class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v282265585"},[a("span",{class:"Generalized"},"m")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") ("),a("a",{id:"v1151704483",class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1304117943"},[a("span",{class:"Generalized"},"o")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(`)
+ ⇒ `),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Path"},[a("span",{class:"Primitive"},"Path")]),s(" ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v2143139988",href:"#v2143139988"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Vec"},[a("span",{class:"Data"},"Vec")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-2b-assoc"},[a("span",{class:"Fn"},"+-assoc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v2143139988"},[a("span",{class:"LocalVar"},"i")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") (("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(") "),a("a",{class:"aya-hover","aya-hover-text":"Vec ((n + m) + o) A",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s(") ("),a("a",{class:"aya-hover","aya-hover-text":"Vec n A",href:"#v765242091"},[a("span",{class:"LocalVar"},"xs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Vec m A",href:"#v1117871068"},[a("span",{class:"LocalVar"},"ys")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec (?n n A m o xs ys zs + ?m n A m o xs ys zs) (?A n A m o xs ys zs)",href:"#Mian-2b2b"},[a("span",{class:"Fn"},"++")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Vec o A",href:"#v1151704483"},[a("span",{class:"LocalVar"},"zs")]),s("))")]),s(`
+`)],-1),a("p",null,"The proof is omitted (try yourself!).",-1),a("h2",{id:"quotient-inductive-types",tabindex:"-1"},[s("Quotient inductive types "),a("a",{class:"header-anchor",href:"#quotient-inductive-types","aria-label":'Permalink to "Quotient inductive types"'},"")],-1),a("p",null,"Quotient types are types that equates their instances in a non-trivial way. In Aya, they are defined using the following syntax:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Interval",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Interval"},[a("span",{class:"Data"},"Interval")]),s(`
+| `),a("a",{id:"Mian-Interval-left",class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(`
+| `),a("a",{id:"Mian-Interval-right",class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")]),s(`
+| `),a("a",{id:"Mian-Interval-line",class:"aya-hover","aya-hover-text":"left = right",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")])]),s(`
+`)],-1),v('
This is an uninteresting quotient type, that is basically Bool but saying its two values are equal, so it's really just a unit type, with its unique element being the equivalence class of left and right.
If you're familiar with a proof assistant with an intensional equality like Coq/Agda/Lean/etc., you might find this surprising because a unit type shall not have two distinct elements, and an equality shall not be stated between two distinct constructors. How does this work in Aya?
Actually, in these systems, the equality is defined inductively, and it only has one constructor -- refl. This is not how equality is defined in Aya, so we can cook some interesting equality proofs into it, which includes these equality-looking constructors.
The type of line will be translated into I → Interval together with the judgmental equality that line0 is left and line1 is right, basically a desugaring of the equality with additional features. This makes line a valid constructor in normal type theory: it takes some parameters and returns Interval.
These judgmental equalities need to be preserved by the elimination rule of Interval. Here is an example elimination:
Note that the term pmap Interval-elim line, which reduces to p, has type Interval-elim left = Interval-elim right, so we need to check if p 0 equals Interval-elim left, and p 1 equals Interval-elim right. This is a confluence check that ensures the elimination is well-defined.
What's interesting about this type, is that its elimination implies function extensionality:
",2),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"private"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-lemma",class:"aya-hover","aya-hover-text":"B",href:"#Mian-lemma"},[a("span",{class:"Fn"},"lemma")]),s(`
+ (`),a("a",{id:"v1872973138",class:"aya-hover","aya-hover-text":"A → B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{id:"v1465346452",class:"aya-hover","aya-hover-text":"A → B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") ("),a("a",{id:"v302366050",class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v302366050"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("span",{class:"Keyword"},"∀"),s(),a("a",{id:"v813823788",class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v813823788"},[a("span",{class:"LocalVar"},"x")]),s(`)
+ (`),a("a",{id:"v2129821055",class:"aya-hover","aya-hover-text":"Interval",href:"#v2129821055"},[a("span",{class:"LocalVar"},"i")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Interval"},[a("span",{class:"Data"},"Interval")]),s(") ("),a("a",{id:"v1225568095",class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(),a("span",{class:"Keyword"},"elim"),s(),a("a",{href:"#v2129821055"},[a("span",{class:"LocalVar"},"i")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-left"},[a("span",{class:"Constructor"},"left")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1872973138"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-right"},[a("span",{class:"Constructor"},"right")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1465346452"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"left = right",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(),a("a",{id:"v451460284",class:"aya-hover","aya-hover-text":"I",href:"#v451460284"},[a("span",{class:"LocalVar"},"j")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v302366050"},[a("span",{class:"LocalVar"},"p")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v1225568095"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v451460284"},[a("span",{class:"LocalVar"},"j")]),s(`
+
+`),a("span",{class:"Keyword"},"example"),s(),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-3aNoExport-funExt27",class:"aya-hover","aya-hover-text":"f = g",href:"#Mian-3aNoExport-funExt27"},[a("span",{class:"Fn"},"funExt'")]),s(" ("),a("a",{id:"v1558103808",class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{id:"v1828873985",class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v370370379"},[a("span",{class:"Generalized"},"A")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#v1068586139"},[a("span",{class:"Generalized"},"B")]),s(") ("),a("a",{id:"v892965953",class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v892965953"},[a("span",{class:"LocalVar"},"p")]),s(" : "),a("span",{class:"Keyword"},"∀"),s(),a("a",{id:"v826865256",class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(" → "),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A",href:"#v826865256"},[a("span",{class:"LocalVar"},"a")]),s(") : "),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(` ⇒
+ `),a("a",{class:"aya-hover","aya-hover-text":"lemma f g p left = lemma f g p right",href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Interval → A → B",href:"#Mian-lemma"},[a("span",{class:"Fn"},"lemma")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1558103808"},[a("span",{class:"LocalVar"},"f")]),s(),a("a",{class:"aya-hover","aya-hover-text":"A → B",href:"#v1828873985"},[a("span",{class:"LocalVar"},"g")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Fn (B : A) → f B = g B",href:"#v892965953"},[a("span",{class:"LocalVar"},"p")]),s(") ("),a("span",{class:"Keyword"},"fn"),s(),a("a",{id:"v1845517769",href:"#v1845517769"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Interval",href:"#Mian-Interval-line"},[a("span",{class:"Constructor"},"line")]),s(),a("a",{class:"aya-hover","aya-hover-text":"I",href:"#v1845517769"},[a("span",{class:"LocalVar"},"i")]),s(")")]),s(`
+`)],-1),a("p",null,[s("Note that even though we are using equation combinators like "),a("code",{class:"Aya"},[a("a",{href:"#Mian-pmap"},[a("span",{class:"Fn"},"pmap")])]),s(" which are implemented using path application and abstraction, it is not considered cheating because these are already theorems in MLTT anyway.")],-1),a("p",null,"We can define other interesting quotients such as a symmetric integer:",-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"open"),s(),a("span",{class:"Keyword"},"inductive"),s(),a("a",{id:"Mian-Int",class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(`
+| `),a("a",{id:"Mian-Int-pos",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(" | "),a("a",{id:"Mian-Int-neg",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| `),a("a",{id:"Mian-Int-zro",class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(" 0 "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-3d"},[a("span",{class:"Fn"},"=")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" 0")]),s(`
+`)],-1),a("p",null,[s("Some operations on "),a("code",{class:"Aya"},[a("a",{href:"#Mian-Int"},[a("span",{class:"Data"},"Int")])]),s(":")],-1),a("pre",{class:"Aya"},[s(""),a("code",null,[a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-succ",class:"aya-hover","aya-hover-text":"Int",href:"#Mian-succ"},[a("span",{class:"Fn"},"succ")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{id:"v380812044",class:"aya-hover","aya-hover-text":"Nat",href:"#v380812044"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v380812044"},[a("span",{class:"LocalVar"},"n")]),s(`)
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" 0 ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(` 1
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(" ("),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-Nat-suc"},[a("span",{class:"Constructor"},"suc")]),s(),a("a",{id:"v846918683",class:"aya-hover","aya-hover-text":"Nat",href:"#v846918683"},[a("span",{class:"LocalVar"},"n")]),s(") ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v846918683"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(),a("a",{id:"v1823923917",class:"aya-hover","aya-hover-text":"I",href:"#v1823923917"},[a("span",{class:"LocalVar"},"i")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(` 1
+
+`),a("span",{class:"Keyword"},"def"),s(),a("a",{id:"Mian-abs",class:"aya-hover","aya-hover-text":"Nat",href:"#Mian-abs"},[a("span",{class:"Fn"},"abs")]),s(),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Int"},[a("span",{class:"Data"},"Int")]),s(" : "),a("a",{class:"aya-hover","aya-hover-text":"Type 0",href:"#Mian-Nat"},[a("span",{class:"Data"},"Nat")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-pos"},[a("span",{class:"Constructor"},"pos")]),s(),a("a",{id:"v1789268516",class:"aya-hover","aya-hover-text":"Nat",href:"#v1789268516"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v1789268516"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"Int",href:"#Mian-Int-neg"},[a("span",{class:"Constructor"},"neg")]),s(),a("a",{id:"v817686795",class:"aya-hover","aya-hover-text":"Nat",href:"#v817686795"},[a("span",{class:"LocalVar"},"n")]),s(" ⇒ "),a("a",{class:"aya-hover","aya-hover-text":"Nat",href:"#v817686795"},[a("span",{class:"LocalVar"},"n")]),s(`
+| `),a("a",{class:"aya-hover","aya-hover-text":"pos 0 = neg 0",href:"#Mian-Int-zro"},[a("span",{class:"Constructor"},"zro")]),s(" _ ⇒ 0")]),s(`
+`)],-1),v('
The succ operator has the first three clauses straightforward, and the last one is a proof of succ(neg0) equals succ(pos0), as we should preserve the judgmental equality in the type of zro. We need to do the same for abs.
',1)]))}const z=g(T,[["render",N]]);export{B as __pageData,z as default};
diff --git a/assets/guide_readings.md.DU4j-4Ox.js b/assets/guide_readings.md.DU4j-4Ox.js
new file mode 100644
index 0000000..c913deb
--- /dev/null
+++ b/assets/guide_readings.md.DU4j-4Ox.js
@@ -0,0 +1 @@
+import{d as k,c as v,j as i,a as s,G as y,k as w,B as C,o as P}from"./chunks/framework.BnE-uSbk.js";const T={name:"Conor McBride",link:"http://strictlypositive.org"},o={name:"Thierry Coquand",link:"https://www.cse.chalmers.se/~coquand"},S={name:"Cyril Cohen",link:"https://perso.crans.org/cohen"},t={name:"András Kovács",link:"https://andraskovacs.github.io"},p={name:"Ambrus Kaposi",link:"https://akaposi.github.io"},r={name:"Simon Huber",link:"https://simhu.github.io"},A={name:"Guillaume Brunerie",link:"https://guillaumebrunerie.github.io"},a={name:"Andreas Abel",link:"https://www.cse.chalmers.se/~abela"},d={name:"Andrea Vezzosi",link:"https://saizan.github.io"},l={name:"Anders Mörtberg",link:"https://staff.math.su.se/anders.mortberg"},h={name:"Jesper Cockx",link:"https://jesper.sikanda.be"},I={name:"Robert Harper",link:"https://www.cs.cmu.edu/~rwh"},n={name:"Carlo Angiuli",link:"https://carloangiuli.com"},c={name:"Daniel Gratzer",link:"https://www.danielgratzer.com"},u={name:"Jon Sterling",link:"https://www.jonmsterling.com"},m={name:"Loïc Pujet",link:"https://pujet.fr"},g={name:"Nicolas Tabareau",link:"https://tabareau.fr"},f={name:"Kuen-Bang Hou (Favonia)",link:"https://favonia.org"},L=[{type:"General Type Theory",items:[{title:"Observational Equality: Now for Good",venue:"POPL 2022",authors:[m,g],links:[["doi","10.1145/3498693"],["conference","https://dl.acm.org/doi/pdf/10.1145/3498693"]]},{title:"Copatterns: programming infinite structures by observations",authors:[a,{name:"Brigitte Pientka"},{name:"David Thibodeau"},{name:"Anton Setzer"}],venue:"POPL 2013",links:[["doi","10.1145/2480359.2429075"],["online","https://www.cse.chalmers.se/~abela/popl13.pdf"]]},{title:"Staged Compilation with Two-Level Type Theory",authors:[t],venue:"ICFP 2022",links:[["github","AndrasKovacs/staged"],["online","https://andraskovacs.github.io/pdfs/2ltt.pdf"],["doi","10.1145/3547641"]]}]},{type:"Universes",items:[{title:"Crude but Effective Stratification",authors:[T],links:[["slides","https://personal.cis.strath.ac.uk/conor.mcbride/Crude.pdf"]]},{title:"Generalized Universe Hierarchies and First-Class Universe Levels",authors:[t],links:[["arxiv","2103.00223"]]},{title:"Dependently typed lambda calculus with a lifting operator",authors:[{name:"Damien Rouhling",link:"https://www-sop.inria.fr/members/Damien.Rouhling"}],links:[["online","https://www-sop.inria.fr/members/Damien.Rouhling/data/internships/M1Report.pdf"]]},{title:"An Order-Theoretic Analysis of Universe Polymorphism",venue:"POPL 2023",authors:[f,n,{name:"Reed Mullanix"}],links:[["online","https://favonia.org/files/mugen.pdf"],["doi","10.1145/3571250"]]},{title:"Impredicative Observational Equality",authors:[g,m],venue:"POPL 2023",links:[["online","https://hal.inria.fr/hal-03857705"],["doi","10.1145/3571739"]]}]},{type:"Equality in Type Theory",items:[{title:"Separating Path and Identity Types in Presheaf Models of Univalent Type Theory",authors:[{name:"Andrew Swan"}],links:[["arxiv","1808.00920"]]},{title:"A Syntax for Higher Inductive-Inductive Types",authors:[p,t],venue:"FSCD 2018",links:[["doi","10.4230/LIPIcs.FSCD.2018.20"]]},{title:"Signatures and Induction Principles for Higher Inductive-Inductive Types",venue:"LMCS 2020",authors:[p,t],links:[["arxiv","1902.00297"],["doi","10.23638/LMCS-16(1:10)2020"]]},{title:"Contributions to Multimode and Presheaf Type Theory",authors:[{name:"Andreas Nuyts"}],links:[["online","https://lirias.kuleuven.be/retrieve/581985"]]}]},{type:"Cubical Type Theory",items:[{title:"Cubical Agda: A Dependently Typed Programming Language with Univalence and Higher Inductive Types",authors:[d,a,l],venue:"ICFP 2019",links:[["doi","10.1145/3341691"],["online","https://staff.math.su.se/anders.mortberg/papers/cubicalagda2.pdf"]]},{title:"Normalization for Cubical Type theory",authors:[u,n],venue:"LICS 2020",links:[["doi","10.1109/LICS52264.2021.9470719"],["arxiv","2101.11479"],["online","https://www.jonmsterling.com/papers/sterling-angiuli-2021.pdf"],["slides","https://www.jonmsterling.com/slides/sterling-angiuli-2021.pdf"]]},{title:"Automating Kan composition",authors:[{name:"Maximilian Doré"}],links:[["slides","https://europroofnet.github.io/assets/wg6/stockholm-kickoff-slides/dore-europroofnet-stockholm-slides.pdf"]]},{title:"Syntax and models of Cartesian cubical type theory",authors:[n,A,o,I,f,{name:"Daniel R. Licata"}],venue:"MSCS 2021",links:[["doi","10.1017/S0960129521000347"],["online","https://www.cs.cmu.edu/~cangiuli/papers/abcfhl.pdf"]]},{title:"A cubical type theory for higher inductive types",authors:[r],links:[["online","https://www.cse.chalmers.se/~simonhu/misc/hcomp.pdf"]]},{title:"Cubical Type Theory: a constructive interpretation of the univalence axiom",venue:"TYPES 2015",authors:[S,o,r,l],links:[["arxiv","1611.02108"],["doi","10.4230/LIPIcs.TYPES.2015.5"]]},{title:"On Higher Inductive Types in Cubical Type Theory",venue:"LICS 2018",authors:[o,r,l],links:[["arxiv","1802.01170"],["doi","10.1145/3209108.3209197"]]},{title:"Computational Semantics of Cartesian Cubical Type Theory",venue:"PhD thesis",authors:[n],links:[["online","https://carloangiuli.com/papers/thesis.pdf"]]},{title:"A Cubical Language for Bishop Sets",venue:"LMCS 2022",authors:[u,n,c],links:[["arxiv","2003.01491"],["doi","10.46298/lmcs-18%281%3A43%292022"]]},{title:"Cubical Syntax for Reflection-Free Extensional Equality",venue:"FSCD 2019",authors:[u,n,c],links:[["arxiv","1904.08562"],["doi","10.4230/LIPIcs.FSCD.2019.31"]]}]},{type:"Implementation",items:[{title:"A Categorical Perspective on Pattern Unification",authors:[d,a],links:[["online","https://saizan.github.io/papers/pattern-unif.pdf"]]},{title:'The "Elaboration Zoo"',authors:[t],links:[["github","AndrasKovacs/elaboration-zoo"]]},{title:"Elaboration with First-Class Implicit Function Types",authors:[t],venue:"ICFP 2020",links:[["github","AndrasKovacs/implicit-fun-elaboration"],["doi","10.1145/3408983"]]},{title:"Higher-Order Constraint Simplification In Dependent Type Theory",authors:[{name:"Jason Reed"}],venue:"LFMTP 2009",links:[["doi","10.1145/1577824.1577832"],["online","https://www.cs.cmu.edu/~jcreed/papers/csl08-hocs.pdf"]]},{title:"Overlapping and Order-Independent Patterns",links:[["online","https://jesper.sikanda.be/files/overlapping-and-order-independent-patterns.pdf"]],authors:[h,{name:"Dominique Devriese"},{name:"Frank Piessens"}]},{title:"Elaborating Dependent (Co)Pattern Matching",links:[["doi","10.1145/3236770"]],authors:[h,a],venue:"ICFP 2018"}]},{type:"Miscellaneous",items:[{title:"Coq's Vibrant Ecosystem for Verification Engineering",venue:"CPP 2022",authors:[{name:"Andrew W. Appel",link:"https://orcid.org/0000-0001-6009-0325"}],links:[["online","https://www.cs.princeton.edu/~appel/papers/ecosystem.pdf"],["doi","10.1145/3497775.3503951"]]},{title:"The End of History? Using a Proof Assistant to Replace Language Design with Library Design",authors:[{name:"Adam Chlipala"},{name:"Benjamin Delaware"},{name:"Samuel Duchovni"},{name:"Jason Gross"},{name:"Clément Pit-Claudel"},{name:"Sorawit Suriyakarn"},{name:"Peng Wang"},{name:"Katherine Ye"}],venue:"SNAPL 2017",links:[["doi","10.4230/LIPIcs.SNAPL.2017.3"],["online","https://drops.dagstuhl.de/opus/volltexte/2017/7123/pdf/LIPIcs-SNAPL-2017-3.pdf"]]}]}],F=JSON.parse('{"title":"Recommended Reading","description":"","frontmatter":{},"headers":[],"relativePath":"guide/readings.md","filePath":"guide/readings.md","lastUpdated":1668050816000}'),D={name:"guide/readings.md"},M=k({...D,setup(x){return(R,e)=>{const b=C("Publications");return P(),v("div",null,[e[0]||(e[0]=i("h1",{id:"recommended-reading",tabindex:"-1"},[s("Recommended Reading "),i("a",{class:"header-anchor",href:"#recommended-reading","aria-label":'Permalink to "Recommended Reading"'},"")],-1)),e[1]||(e[1]=i("p",null,"This is a list of documents that are helpful or simply related to the design & implementation of Aya, randomly ordered.",-1)),e[2]||(e[2]=i("p",null,[s("Beware that you are encouraged to suggest changes to this page! Just go to the bottom of this page and there will be a link. Apart from this list, Jon Sterling's "),i("a",{href:"https://www.jonmsterling.com/cubical-bibliography.html",target:"_blank",rel:"noreferrer"},"cubical bibliography"),s(" is also a good source of information.")],-1)),y(b,{pubs:w(L)},null,8,["pubs"])])}}});export{F as __pageData,M as default};
diff --git a/assets/guide_readings.md.DU4j-4Ox.lean.js b/assets/guide_readings.md.DU4j-4Ox.lean.js
new file mode 100644
index 0000000..c913deb
--- /dev/null
+++ b/assets/guide_readings.md.DU4j-4Ox.lean.js
@@ -0,0 +1 @@
+import{d as k,c as v,j as i,a as s,G as y,k as w,B as C,o as P}from"./chunks/framework.BnE-uSbk.js";const T={name:"Conor McBride",link:"http://strictlypositive.org"},o={name:"Thierry Coquand",link:"https://www.cse.chalmers.se/~coquand"},S={name:"Cyril Cohen",link:"https://perso.crans.org/cohen"},t={name:"András Kovács",link:"https://andraskovacs.github.io"},p={name:"Ambrus Kaposi",link:"https://akaposi.github.io"},r={name:"Simon Huber",link:"https://simhu.github.io"},A={name:"Guillaume Brunerie",link:"https://guillaumebrunerie.github.io"},a={name:"Andreas Abel",link:"https://www.cse.chalmers.se/~abela"},d={name:"Andrea Vezzosi",link:"https://saizan.github.io"},l={name:"Anders Mörtberg",link:"https://staff.math.su.se/anders.mortberg"},h={name:"Jesper Cockx",link:"https://jesper.sikanda.be"},I={name:"Robert Harper",link:"https://www.cs.cmu.edu/~rwh"},n={name:"Carlo Angiuli",link:"https://carloangiuli.com"},c={name:"Daniel Gratzer",link:"https://www.danielgratzer.com"},u={name:"Jon Sterling",link:"https://www.jonmsterling.com"},m={name:"Loïc Pujet",link:"https://pujet.fr"},g={name:"Nicolas Tabareau",link:"https://tabareau.fr"},f={name:"Kuen-Bang Hou (Favonia)",link:"https://favonia.org"},L=[{type:"General Type Theory",items:[{title:"Observational Equality: Now for Good",venue:"POPL 2022",authors:[m,g],links:[["doi","10.1145/3498693"],["conference","https://dl.acm.org/doi/pdf/10.1145/3498693"]]},{title:"Copatterns: programming infinite structures by observations",authors:[a,{name:"Brigitte Pientka"},{name:"David Thibodeau"},{name:"Anton Setzer"}],venue:"POPL 2013",links:[["doi","10.1145/2480359.2429075"],["online","https://www.cse.chalmers.se/~abela/popl13.pdf"]]},{title:"Staged Compilation with Two-Level Type Theory",authors:[t],venue:"ICFP 2022",links:[["github","AndrasKovacs/staged"],["online","https://andraskovacs.github.io/pdfs/2ltt.pdf"],["doi","10.1145/3547641"]]}]},{type:"Universes",items:[{title:"Crude but Effective Stratification",authors:[T],links:[["slides","https://personal.cis.strath.ac.uk/conor.mcbride/Crude.pdf"]]},{title:"Generalized Universe Hierarchies and First-Class Universe Levels",authors:[t],links:[["arxiv","2103.00223"]]},{title:"Dependently typed lambda calculus with a lifting operator",authors:[{name:"Damien Rouhling",link:"https://www-sop.inria.fr/members/Damien.Rouhling"}],links:[["online","https://www-sop.inria.fr/members/Damien.Rouhling/data/internships/M1Report.pdf"]]},{title:"An Order-Theoretic Analysis of Universe Polymorphism",venue:"POPL 2023",authors:[f,n,{name:"Reed Mullanix"}],links:[["online","https://favonia.org/files/mugen.pdf"],["doi","10.1145/3571250"]]},{title:"Impredicative Observational Equality",authors:[g,m],venue:"POPL 2023",links:[["online","https://hal.inria.fr/hal-03857705"],["doi","10.1145/3571739"]]}]},{type:"Equality in Type Theory",items:[{title:"Separating Path and Identity Types in Presheaf Models of Univalent Type Theory",authors:[{name:"Andrew Swan"}],links:[["arxiv","1808.00920"]]},{title:"A Syntax for Higher Inductive-Inductive Types",authors:[p,t],venue:"FSCD 2018",links:[["doi","10.4230/LIPIcs.FSCD.2018.20"]]},{title:"Signatures and Induction Principles for Higher Inductive-Inductive Types",venue:"LMCS 2020",authors:[p,t],links:[["arxiv","1902.00297"],["doi","10.23638/LMCS-16(1:10)2020"]]},{title:"Contributions to Multimode and Presheaf Type Theory",authors:[{name:"Andreas Nuyts"}],links:[["online","https://lirias.kuleuven.be/retrieve/581985"]]}]},{type:"Cubical Type Theory",items:[{title:"Cubical Agda: A Dependently Typed Programming Language with Univalence and Higher Inductive Types",authors:[d,a,l],venue:"ICFP 2019",links:[["doi","10.1145/3341691"],["online","https://staff.math.su.se/anders.mortberg/papers/cubicalagda2.pdf"]]},{title:"Normalization for Cubical Type theory",authors:[u,n],venue:"LICS 2020",links:[["doi","10.1109/LICS52264.2021.9470719"],["arxiv","2101.11479"],["online","https://www.jonmsterling.com/papers/sterling-angiuli-2021.pdf"],["slides","https://www.jonmsterling.com/slides/sterling-angiuli-2021.pdf"]]},{title:"Automating Kan composition",authors:[{name:"Maximilian Doré"}],links:[["slides","https://europroofnet.github.io/assets/wg6/stockholm-kickoff-slides/dore-europroofnet-stockholm-slides.pdf"]]},{title:"Syntax and models of Cartesian cubical type theory",authors:[n,A,o,I,f,{name:"Daniel R. Licata"}],venue:"MSCS 2021",links:[["doi","10.1017/S0960129521000347"],["online","https://www.cs.cmu.edu/~cangiuli/papers/abcfhl.pdf"]]},{title:"A cubical type theory for higher inductive types",authors:[r],links:[["online","https://www.cse.chalmers.se/~simonhu/misc/hcomp.pdf"]]},{title:"Cubical Type Theory: a constructive interpretation of the univalence axiom",venue:"TYPES 2015",authors:[S,o,r,l],links:[["arxiv","1611.02108"],["doi","10.4230/LIPIcs.TYPES.2015.5"]]},{title:"On Higher Inductive Types in Cubical Type Theory",venue:"LICS 2018",authors:[o,r,l],links:[["arxiv","1802.01170"],["doi","10.1145/3209108.3209197"]]},{title:"Computational Semantics of Cartesian Cubical Type Theory",venue:"PhD thesis",authors:[n],links:[["online","https://carloangiuli.com/papers/thesis.pdf"]]},{title:"A Cubical Language for Bishop Sets",venue:"LMCS 2022",authors:[u,n,c],links:[["arxiv","2003.01491"],["doi","10.46298/lmcs-18%281%3A43%292022"]]},{title:"Cubical Syntax for Reflection-Free Extensional Equality",venue:"FSCD 2019",authors:[u,n,c],links:[["arxiv","1904.08562"],["doi","10.4230/LIPIcs.FSCD.2019.31"]]}]},{type:"Implementation",items:[{title:"A Categorical Perspective on Pattern Unification",authors:[d,a],links:[["online","https://saizan.github.io/papers/pattern-unif.pdf"]]},{title:'The "Elaboration Zoo"',authors:[t],links:[["github","AndrasKovacs/elaboration-zoo"]]},{title:"Elaboration with First-Class Implicit Function Types",authors:[t],venue:"ICFP 2020",links:[["github","AndrasKovacs/implicit-fun-elaboration"],["doi","10.1145/3408983"]]},{title:"Higher-Order Constraint Simplification In Dependent Type Theory",authors:[{name:"Jason Reed"}],venue:"LFMTP 2009",links:[["doi","10.1145/1577824.1577832"],["online","https://www.cs.cmu.edu/~jcreed/papers/csl08-hocs.pdf"]]},{title:"Overlapping and Order-Independent Patterns",links:[["online","https://jesper.sikanda.be/files/overlapping-and-order-independent-patterns.pdf"]],authors:[h,{name:"Dominique Devriese"},{name:"Frank Piessens"}]},{title:"Elaborating Dependent (Co)Pattern Matching",links:[["doi","10.1145/3236770"]],authors:[h,a],venue:"ICFP 2018"}]},{type:"Miscellaneous",items:[{title:"Coq's Vibrant Ecosystem for Verification Engineering",venue:"CPP 2022",authors:[{name:"Andrew W. Appel",link:"https://orcid.org/0000-0001-6009-0325"}],links:[["online","https://www.cs.princeton.edu/~appel/papers/ecosystem.pdf"],["doi","10.1145/3497775.3503951"]]},{title:"The End of History? Using a Proof Assistant to Replace Language Design with Library Design",authors:[{name:"Adam Chlipala"},{name:"Benjamin Delaware"},{name:"Samuel Duchovni"},{name:"Jason Gross"},{name:"Clément Pit-Claudel"},{name:"Sorawit Suriyakarn"},{name:"Peng Wang"},{name:"Katherine Ye"}],venue:"SNAPL 2017",links:[["doi","10.4230/LIPIcs.SNAPL.2017.3"],["online","https://drops.dagstuhl.de/opus/volltexte/2017/7123/pdf/LIPIcs-SNAPL-2017-3.pdf"]]}]}],F=JSON.parse('{"title":"Recommended Reading","description":"","frontmatter":{},"headers":[],"relativePath":"guide/readings.md","filePath":"guide/readings.md","lastUpdated":1668050816000}'),D={name:"guide/readings.md"},M=k({...D,setup(x){return(R,e)=>{const b=C("Publications");return P(),v("div",null,[e[0]||(e[0]=i("h1",{id:"recommended-reading",tabindex:"-1"},[s("Recommended Reading "),i("a",{class:"header-anchor",href:"#recommended-reading","aria-label":'Permalink to "Recommended Reading"'},"")],-1)),e[1]||(e[1]=i("p",null,"This is a list of documents that are helpful or simply related to the design & implementation of Aya, randomly ordered.",-1)),e[2]||(e[2]=i("p",null,[s("Beware that you are encouraged to suggest changes to this page! Just go to the bottom of this page and there will be a link. Apart from this list, Jon Sterling's "),i("a",{href:"https://www.jonmsterling.com/cubical-bibliography.html",target:"_blank",rel:"noreferrer"},"cubical bibliography"),s(" is also a good source of information.")],-1)),y(b,{pubs:w(L)},null,8,["pubs"])])}}});export{F as __pageData,M as default};
diff --git a/assets/guide_vscode-tutorial.md.Bwg1aD-U.js b/assets/guide_vscode-tutorial.md.Bwg1aD-U.js
new file mode 100644
index 0000000..a9ef0de
--- /dev/null
+++ b/assets/guide_vscode-tutorial.md.Bwg1aD-U.js
@@ -0,0 +1 @@
+import{_ as o,c as t,a2 as a,o as r}from"./chunks/framework.BnE-uSbk.js";const p=JSON.parse('{"title":"So you are using VSCode","description":"","frontmatter":{},"headers":[],"relativePath":"guide/vscode-tutorial.md","filePath":"guide/vscode-tutorial.md","lastUpdated":1689586300000}'),s={name:"guide/vscode-tutorial.md"};function i(n,e,d,c,l,h){return r(),t("div",null,e[0]||(e[0]=[a('
Go to GitHub Releases, click the latest successful run, scroll down to the bottom of the page, download the "aya-prover-vscode-extension", and unzip it. Then, follow VSCode docs to install the extension.
It remains to configure the Aya language server. There are two ways to use the server. First, open settings, search for "Aya path", you should see a text box. Then, you have a choice:
Use a jar file. Put your lsp-fatjar.jar file path there. Make sure you have a java executable in the Path (recommended) or in java.home key in the settings json.
Use the jlink version of Aya. Put the aya-lsp (or aya-lsp.bat if you are on Windows) file path there, which is under the bin folder of the jlink distribution. In this case, you don't need to have a java executable in the Path.
Then, open a directory that is an Aya project (see project-tutorial). Open any .aya file, you should see some basic highlight (keywords, comments, etc.). Wait for VSCode to activate the extension, and hit Ctrl+L Ctrl+L to load the file. At this point, you should see advanced highlight (type names, constructors, etc.), with clickable definitions.
The rest of the features should be quite discoverable for regular programmers, such as hovering a red or a yellow wavy line to see the error message, etc. Please create issues and discuss ideas on how to improve the error reports.
',6)]))}const f=o(s,[["render",i]]);export{p as __pageData,f as default};
diff --git a/assets/guide_vscode-tutorial.md.Bwg1aD-U.lean.js b/assets/guide_vscode-tutorial.md.Bwg1aD-U.lean.js
new file mode 100644
index 0000000..a9ef0de
--- /dev/null
+++ b/assets/guide_vscode-tutorial.md.Bwg1aD-U.lean.js
@@ -0,0 +1 @@
+import{_ as o,c as t,a2 as a,o as r}from"./chunks/framework.BnE-uSbk.js";const p=JSON.parse('{"title":"So you are using VSCode","description":"","frontmatter":{},"headers":[],"relativePath":"guide/vscode-tutorial.md","filePath":"guide/vscode-tutorial.md","lastUpdated":1689586300000}'),s={name:"guide/vscode-tutorial.md"};function i(n,e,d,c,l,h){return r(),t("div",null,e[0]||(e[0]=[a('
Go to GitHub Releases, click the latest successful run, scroll down to the bottom of the page, download the "aya-prover-vscode-extension", and unzip it. Then, follow VSCode docs to install the extension.
It remains to configure the Aya language server. There are two ways to use the server. First, open settings, search for "Aya path", you should see a text box. Then, you have a choice:
Use a jar file. Put your lsp-fatjar.jar file path there. Make sure you have a java executable in the Path (recommended) or in java.home key in the settings json.
Use the jlink version of Aya. Put the aya-lsp (or aya-lsp.bat if you are on Windows) file path there, which is under the bin folder of the jlink distribution. In this case, you don't need to have a java executable in the Path.
Then, open a directory that is an Aya project (see project-tutorial). Open any .aya file, you should see some basic highlight (keywords, comments, etc.). Wait for VSCode to activate the extension, and hit Ctrl+L Ctrl+L to load the file. At this point, you should see advanced highlight (type names, constructors, etc.), with clickable definitions.
The rest of the features should be quite discoverable for regular programmers, such as hovering a red or a yellow wavy line to see the error message, etc. Please create issues and discuss ideas on how to improve the error reports.