

Running Circles Around (In) Your Proof Assistant; or, Quotients that Compute | H...
source link: https://homotopytypetheory.org/2011/04/23/running-circles-around-in-your-proof-assistant/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

Running Circles Around (In) Your Proof Assistant; or, Quotients that Compute
Higher-dimensional inductive types are an idea that many people have been kicking around lately; for example, in An Interval Type Implies Function Extensionality. The basic idea is that you define a type by specifying both what it’s elements are (as usual), and what the paths/equivalences between them are, and what the paths between paths are, etc. This lets you specify interesting topological spaces, like the interval, the circle, the sphere, the 2-sphere, …, and will have programming applications as well. What I’d like to talk about in this post in a little trick for working with higher-dimensional inductives in current proof assistants, like Agda and Coq. This trick makes them more convenient to work with than the first thing you might try, which is to simply postulate them: somewhat surprisingly, we can make some of the computational behavior of their elimination rules hold definitionally, rather than propositionally.
For example, the interval is the least type consisting of two points and a path between them.
One way to add such a type to Agda and Coq is to postulate it using axioms. For example, here’s what the interval looks like in Agda using this approach:
postulate I : Set Zero : I One : I seg : Zero ≃ One I-rec : {C : Set} -> (a b : C) -> (p : a ≃ b) -> I -> C compβ0 : {C : Set} -> (a b : C) -> (p : a ≃ b) -> I-rec a b p Zero ≃ a compβ1 : {C : Set} -> (a b : C) -> (p : a ≃ b) -> I-rec a b p One ≃ b compβseg : {C : Set} -> (a b : C) -> (p : a ≃ b) -> resp (I-rec a b p) seg ≃ trans (compβ0 _ _ _) (trans p (sym (compβ1 _ _ _)))
That is, we postulate a type I; terms Zero and One; and an elimination rule I-rec, which says that you can map I into a type C by giving two points of C with a path between them. We also postulate computation rules: At the term level, I-rec takes Zero and One to the specified points. A term can be “applied” to a path using resp:
resp : {A C : Set} {M N : A} (f : A -> C) -> Id M N -> Id (f M) (f N)
which gives the action on paths/morphisms of a term.
At the path level, I-rec takes seg to the given path p.
These equations are all computational, β-like, rules, and thus should hold as definitional equations, rather than propositional equivalences. Otherwise, we need to use a propositional equality every time we want to know that if true then e1 else e2 is equal to e1, which makes using these types pretty annoying. (Indeed, we probably should extend the above with an additional postulate stating that any two proofs of I-rec a b p Zero ≃ a are equal—i.e. we want it to be contractible, not just inhabited. Otherwise we could get into a situation where we have two seemingly different proofs of what should be a definitional equation.) However, there is no way to postulate new definitional equalities in Agda or Coq. So this is the best we can do, right?
Not quite! We can make the term-level equations hold definitionally:
I-rec a b _ Zero = a I-rec a b _ One = b
How? Rather than postulating the interval (in which case the elimination rule doesn’t compute), we define it, but as an abstract type! In particular, we define a module that exports the following:
I : Set zero : I one : I seg : zero ≃ one I-rec : {C : Set} -> (a b : C) -> (p : a ≃ b) -> I -> C I-rec a b _ zero = a I-rec a b _ one = b βseg : {C : Set} -> (a b : C) -> (p : a ≃ b) -> resp (I-rec a b p) seg ≃ p
Clients of this module know that there is a type I, terms zero and one and seg and I-rec, such that the computational rules for zero and one hold. They also know that the computation rule for paths holds propositionally (this is unfortunate, but it’s the best we can do). And, because I is an abstract type, that’s all they know—they do not know how I is implemented.
This is good, because we’re going to implement it in an unsafe way: inside the module, I
is defined to be the discrete two-point type. This means that it is inconsistent to postulate zero ≃ one, because we can write functions that distinguish them—inside the implementation, they’re just booleans. So why don’t we get into trouble? First, we have carefully designed the interface so that clients of it cannot distinguish zero and one (up to homotopy): the only way to use an I is I-rec, which ensures that you take zero and one to equivalent results. Second, by the magic of type abstraction, this means that any program written using this interface is safe. Even through there are programs that can be written if you know the implementation of I that are not. This is very basic idea, so basic that we teach it to freshmen.
Here’s what this looks like in Agda
module Interval where private data I' : Set where Zero : I' One : I' I : Set I = I' zero : I zero = Zero one : I one = One I-rec : {C : Set} -> (a b : C) -> (p : a ≃ b) -> I -> C I-rec a b _ Zero = a I-rec a b _ One = b postulate seg : zero ≃ one βseg : {C : Set} -> (a b : C) -> (p : a ≃ b) -> resp (I-rec a b p) seg ≃ p
The module Interval has a private datatype I'. The type I is defined to be I', but because I' is not exported, clients of the module cannot get at its constructors, and in particular cannot pattern-match against it. This means that the only elimination forms for I are those that are defined publicly–namely I-rec. I-rec ignores the path argument, simply computes to the appropriate answer for each constructor. This makes the reduction rules hold. Finally, we postulate seg and its reduction rule.
This makes higher-dimensional inductives much easier to work with, because they compute! It also makes the proof of function extensionality go through:
ext : (A B : Set) (f g : A -> B) (α : (x : A) -> f x ≃ g x) -> f ≃ g ext A B f g α = resp h seg where h : (I -> A -> B) h = (λ i x → I-rec (f x) (g x) (α x) i)
It’s not provable (unless you have function extensionality already!) when the computation rules only hold propositionally.
Recommend
-
8
The Universal Property of QuotientsThe Universal Property of Quotients 11/15/20 ...
-
9
Every proof assistant: Epigram 2 - Autopsy, Obituary, Apology This week shall witness a performance by Conor McBride. Epigram 2: Autopsy, Obituary, Apology Time: Thurs...
-
11
Every proof assistant: redtt This week the speaker will be Jon Sterling, and we are getting two proof assistants for the price of one! redtt and the future of Cartesian cubical type...
-
9
Every proof assistant: Beluga We are marching on with the Every proof assistant series! Mechanizing Meta-Theory in Beluga Time: Thursday, May 28, 2020 from 16:00 to 17...
-
9
Every proof assistant: MMT I am happy to announce the next seminar in the "Every proof assistant" series. MMT: A Foundation-Independent Logical System Time: Thursday,...
-
12
Every proof assistant: Arend For a while now I have been contemplating a series of seminars titled "Every proof assistant" that would be devoted to all the different proof assistants out there. Apart from the e...
-
6
Running Python Workloads on Scalable Snowflake Compute ClustersWhat do you do if you have an old & slow notebook, a 160 million row dataset containing customer reviews that you have to perform sentiment analy...
-
7
Teardown: KC Bearifone Could Talk Circles Around Teddy Ruxpin ...
-
9
Vinyl Sales Ran Circles Around CDs In 2022
-
3
Math Proof Draws New Boundaries Around Black Hole Formation For a half century, mathematicians have tried to define the exact circumstances under...
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK