© 2021 Steven Obua

A Bicycle for Your Mathematical Mind

Cite as: https://doi.org/10.47757/practal.1

July 17th, 2021

This is a ﬁrst sketch of the design of Practal, an interactive theorem proving system for practical logic.

The foundation of many popular interactive theorem proving (ITP) systems [1] (e.g. Isabelle, HOL Light, Coq, Lean, PVS) is a *logic* based on *types*. These types include at least a type ℙ of *propositions*, and a type α → β of *functions*, where α and β are themselves arbitrary types.

I agree with the importance of types for ITP, especially for the formalization of mathematics. Ganesalingam [2] discusses in detail the role of type in mathematics. Nevertheless it seems to me that popular ITP systems do not capture the notion of type in quite the right way to accommodate common mathematical use. Isabelle/HOL and HOL Light for example are based on simply-typed higher-order logic (HOL), which is often suﬃcient for purposes of program veriﬁcation, and astonishingly versatile [3]. But the simple types of HOL do not allow for dependent typing; the type of real square matrices with $n$ rows and columns cannot be expressed in HOL as a type in a straightforward way (although Harrison did it anyway [4]). On the other hand, dependent types [5] as implemented in Coq or Lean bestow a lot of power onto types via the proposition as types [6] paradigm (see also the Xena blog for a discussion), but do not even allow for the common mathematical practice of *subtyping* (neither does HOL). Instead, *coercions* are used to emulate some of the advantages of subtyping.

Impressive results have been obtained with current ITP technology, a recent one being the *Liquid Tensor Experiment*, a formalization in Lean based on ideas of Fields medallist Peter Scholze.

Still, in my opinion, ITP technology has not yet progressed as far as one could reasonably hope for. Among other things, there are two things I would like to do with an ITP system:

- Pick a book or paper, and formalize its ideas within the ITP system to build and further my understanding.
- Formalize my own notions and ideas (e.g. Local Lexing [7]) for the same reasons.

Both of these things are already possible with current ITP systems. But there is a caveat: It takes too much time and effort to do so. I want the ITP system to be a true bicycle for my mind that sharpens and accelerates my thinking, not a heavy boulder that I need to roll up a hill, consuming all of my energy. This also implies that the results of the formalization, including the proofs it contains, are in close correspondence with how I actually think about the notion at hand. I want a system for *practical logic*. I want **Practal**.

So how to get there? In the end, an ITP system is just software. So all the usual advice for making software applies. Probably the most important such advice is to gather requirements and feedback from actual and prospective users. As a start, I will ﬁll this user role myself. But you are invited to become a user of Practal as well!

My design methodology will be to just do with Practal what I would like to do with an ITP system. The diﬃculty is of course that Practal does not exist yet, but I will just pretend that it does. Concretely, I will write down formalizations that I *wish* Practal would understand. Of course I will also have in mind what I believe Practal *will be able to do*, but a major driver will be *what I want it to do*.

In particular, I will not start from a particular logic and type system, and then build everything around it. Instead, I will let *use cases* shape both. This might lead to intermediate inconsistencies, which can hopefully be ﬁxed along the way. Note that this approach is the opposite to how ITP systems are usually designed: First comes the logic / type system as a given, and then users are invited to ﬁnd ingenious solutions to their formalization needs!

In the rest of this paper I will examine ﬁrst use cases, and outline initial design decisions for Practal.

In my opinion, the ability to apply both dependent typing and subtyping together is essential to a natural formalization of mathematics. Let’s consider the following hypothetical deﬁnition of categories in Practal:

structure Category = type Object type Arrow let dom : Arrow → Object let cod : Arrow → Object def HomSet(A : Object, B : Object) = { f : Arrow | dom f = A ∧ cod f = B } let id : (x : Object) → HomSet(x, x) let then : (f : Arrow) → (g : Arrow | dom g = cod f) → { h : Arrow | dom h = dom f ∧ cod h = cod g } axiom identity : ∀ x : Arrow. (x then id (cod x)) = (id (dom x) then x) = x axiom associativity : ∀ e f g : Arrow. ((e then f) then g) = (e then (f then g)) end

Just for this simple example we are already heavily using dependent types in the form of dependent ordered pairs to form the structure itself, and dependent function types for elements of the structure like then. These are combined with predicate subtypes [8] as

{ f : Arrow | dom f = A ∧ cod f = B }

for the deﬁnition of HomSet(A, B). It is a term of type Arrow → ℙ and can itself be viewed as a type, in particular a *subtype* of Arrow.

The notation (g : Arrow | dom g = cod f) in the declaration of then is short for

(g : { g : Arrow | dom g = cod f })

Note that the axiom for associativity does not include the precondition

cod e = dom f ∧ cod f = dom g

This is because if this condition is not met, then both (e then f) then g = nil holds as well as e then (f then g) = nil, which makes (e then f) then g = e then (f then g) true anyway.

Note that equality is a special operator. It takes two arguments, and returns whether they are equal or not. Its type would be = : Any → Any → ℙ, but because there is no Any type in Practal, equality does not have a type.

In the above use case, why does (e then f) then g = nil hold when the precondition is not met?

It is because for any function f : A → B and an argument x such that ¬(x : A), i.e. *not* x : A, we deﬁne f x to be equal to nil, where nil is the only value of type Nil. We also deﬁne that nil applied to any argument x yields nil, that is nil x = nil.

So assume cod e ≠ dom f. This implies e then f = nil, because ¬(f : { g : Arrow | dom g = dom e}). Thus ((e then f) then g) = (nil then g). Now, we would certainly think that ¬(nil : Arrow), and therefore furthermore (nil then g) = nil. We can arrange for this indeed being the case by letting the declaration type Arrow being an abbreviation for

let Arrow : Type axiom ¬(nil : Arrow)

Similarly, assume now cod f ≠ dom g. If e then f is deﬁned, then cod (e then f) = cod f and therefore (e then f) then g = nil.

In our approach, nil is just a normal value; there is nothing special about it except for a few conventions that make it easy for nil to represent undeﬁnedness or optionality. We will say more about this in a later section →.

Given that Practal supports predicate subtyping, it is natural to ask which other subtyping relationships exist. In particular, given two function types A → B and C → D, when do we consider A → B to be a subtype of C → D, in symbols A → B ≤ C → D?

A natural convention, for example used by Aspinall and Compagnoni [9], would be to treat A → B ≤ C → D as being equivalent to

C ≤ A ∧ B ≤ D

This is problematic. Consider two functions floor : ℝ → ℤ and ceiling : ℝ → ℤ which round down and round up, respectively, a real number to an integer. Clearly floor ≠ ceiling. But if we allowed above subtyping convention, then floor and ceiling would both also have type ℤ → ℤ. But floor : ℤ → ℤ is just the identity, and ceiling : ℤ → ℤ is just the identity as well, so we would now have to conclude floor = ceiling!

The problem here is that in a logic we are often interested in whether two functions f and g are equal, i.e. whether f = g holds. In a programming language, this is usually not something we are interested in, as f = g is generally not computable anyway, and therefore of no interest. But in our logic, two functions f : A → B and g : A → B are equal iff

∀ x : A. f x = g x

holds. Therefore, in order to talk consistently about function equality, we need to be able to uniquely determine the domain A of any function f. We therefore treat A → B ≤ C → D as being equivalent to

A = C ∧ B ≤ D

instead. While somewhat unconventional, it is in line with how the PVS system treats function subtyping [8].

Note that this is also in line with our notion of undeﬁnedness for function application. If a function f : A → B could also have type f : C → B with A ≠ C, then there would be no consistent answer to the question if f x is deﬁned or not, because we could have x : A but ¬(x : C) (or the other way around).

Given that we allow subtypes, it makes sense to also allow both union types A ∪ B and intersection types A ∩ B. Naturally, we have

A ≤ A ∪ B ∧ B ≤ A ∪ B

for unions, and

A ∩ B ≤ A ∧ A ∩ B ≤ B

for intersections. An intersection can be empty, of course, and there is a type Null to accommodate this fact, i.e.

¬ (∃x : Null. true)

Unions and intersections can be characterized as follows:

∀ A B : Type. ∀ a : A. (a : B) = (a : A ∩ B) ∀ A B : Type. ∀ b : B. (b : A) = (b : A ∩ B) ∀ A B : Type. ∀ a : A. a : A ∪ B ∀ A B : Type. ∀ b : B. b : A ∪ B

Similarly, it is also possible to form the difference A \ B of two types.

An obvious question is, when are two types equal? The logical answer seems to be to treat types just like you would treat sets: They are equal if they have the same members:

∀ A B : Type. (A = B) = ((∀ a : A. a : B) ∧ (∀ b : B. b : A))

Partial functions can be modelled as total functions which can also return nil:

typealias A ↪ B = A → (B ∪ Nil)

Note that we have

A → B ≤ A ↪ B

because function subtyping is covariant in the codomain.

In Farmer’s *traditional approach to undeﬁnedness* [10], terms can be undeﬁned, but propositions are always deﬁned by considering atomic propositions containing undeﬁned terms to be false.

Farmer’s approach avoids three-valued truth values as in strong Kleene logic [11]. This is certainly a good thing as our goal is to emulate mathematical practice. Therefore in Practal, values in ℙ are also just true or false. But when considered in a truth context, we treat nil the same way as false. That makes sense, because just as we cannot prove a theorem false we neither can prove a theorem nil. This justiﬁcation might sound silly; after all we also cannot prove a theorem 3, yet we do not consider 3 to mean false. But it is the pragmatic answer to the fact that nil can show up in a truth context, while 3 will not. For example, consider the formula

1/0 < 2

Is this a theorem? No, of course it is not. But then, because of (1/0 < 2) = nil, nil is not true, i.e. nil is false.

Therefore we utilise Practal’s support for subtyping and simply deﬁne our logical connectives on ℙ ∪ Nil instead of just on ℙ: $\begin{array}{c|c}
{\includegraphics[height=0.5em]{803ACEEC-1A6D-43D3-B265-CE51934CA499}} & {\includegraphics[height=0.5em]{E23D9C37-FBEC-4C71-9EDC-C8B8CED2E7A1}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{E989A33D-0EE4-4ABB-82AD-FF4744453AA0}} & {\includegraphics[height=0.5em]{4EE2A4E6-6997-42B2-AC09-0F642ECAF322}} \\
{\includegraphics[height=0.5em]{B21BD63B-BBCE-4BB6-9709-73E10153AE32}} & {\includegraphics[height=0.5em]{CE974D59-0279-4596-8BA9-0A5ECCC60AB3}} \\
{\includegraphics[height=0.5em]{6971426C-BAF3-4AFD-8C22-F6644C9FFA06}} & {\includegraphics[height=0.5em]{49F1DAF0-B9D9-467C-B864-0F9B554B96FD}} \\
{\includegraphics[height=0.5em]{B4E6FDE3-533F-47BC-BD83-CDF099343A08}} & {\includegraphics[height=0.5em]{5DDB5759-4ACC-47F3-A12E-A75471F5DA0E}} \\
{\includegraphics[height=0.5em]{F38689D1-FE00-455B-9870-D65344EC1245}} & {\includegraphics[height=0.5em]{604BFC00-150A-40C2-8A72-76424991E7FA}} \\
\end{array}$ Our strategy for deﬁning the connectives is simple; because we consider nil and false from a truth perspective to be the same, we convert all nil arguments to false before computing the result. Proceeding in this way, we obtain the following tables for ∧, ∨, ⟶ and ¬: $\begin{array}{cc}
\begin{array}{c|ccc}
{\includegraphics[height=0.5em]{75D2E22B-60A8-4521-9DCF-332AF48E0106}} & {\includegraphics[height=0.5em]{24D723A7-CC76-4EF4-9C0C-461E3373F320}} & {\includegraphics[height=0.5em]{9A205C02-8608-41DD-B0A4-3558299FFD41}} & {\includegraphics[height=0.5em]{430D00EF-A1E0-474C-8716-540816D5C783}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{755061E8-9CB7-4888-8382-5572342C9306}} & {\includegraphics[height=0.5em]{7998CB3D-4884-4D3C-87D4-DF771FFA8D19}} & {\includegraphics[height=0.5em]{09A1006A-D56E-4D6D-AF9F-43CF8713062F}} & {\includegraphics[height=0.5em]{1BFE8745-98AE-4E78-B34D-C942FA404122}} \\
{\includegraphics[height=0.5em]{74BDEDF4-691A-46B1-8B4B-4B5C43F7347F}} & {\includegraphics[height=0.5em]{46E5CDCA-4C69-482E-A482-2C6BC8DC607C}} & {\includegraphics[height=0.5em]{07F76F76-66D5-44AB-821C-8F48C6ADF921}} & {\includegraphics[height=0.5em]{1A235874-018E-48E7-A959-40369E64E802}} \\
{\includegraphics[height=0.5em]{333C07A3-E496-4005-8935-2F2A7BC64B26}} & {\includegraphics[height=0.5em]{AD16EA96-28C6-4A9C-9A1E-F8D06150FC2F}} & {\includegraphics[height=0.5em]{64ECD38E-1004-446D-9D5E-75D9E7F7E988}} & {\includegraphics[height=0.5em]{0B000193-D6EA-4253-8E21-431384FFBA5B}}
\end{array}
&
\begin{array}{c|ccc}
{\includegraphics[height=0.5em]{81DDCB96-FA8E-43AF-86C0-58F418B587EA}} & {\includegraphics[height=0.5em]{20A5E4DE-583B-476E-BF7A-B60D1B514A4C}} & {\includegraphics[height=0.5em]{63C12DB1-275C-46D6-8A74-46E0FF6C1F39}} & {\includegraphics[height=0.5em]{0001DA97-DF13-49FF-985F-A2D0E6E3DF76}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{1F5241B7-7D4D-4E02-8928-51931E0F700E}} & {\includegraphics[height=0.5em]{1280D18A-3D73-4346-82B1-F85457C475EC}} & {\includegraphics[height=0.5em]{CF8F2DD3-9B07-42C8-A022-3D482DC545CE}} & {\includegraphics[height=0.5em]{E43643C6-A73E-4E31-9B39-41780E254659}} \\
{\includegraphics[height=0.5em]{6AB49EAD-CC51-4F9A-B683-0F6E123CA0A5}} & {\includegraphics[height=0.5em]{6BE9313A-60E2-4E98-BAD4-DD8885507236}} & {\includegraphics[height=0.5em]{E61A0EEF-FEB3-43B7-9FF7-8CE748D4E204}} & {\includegraphics[height=0.5em]{B59E3A15-D6EF-4612-8136-1AC820A93484}} \\
{\includegraphics[height=0.5em]{100DE0F0-B362-43F3-9F61-935A7BAB3EEC}} & {\includegraphics[height=0.5em]{C298B22D-7343-4D37-9EEE-97AA920E3680}} & {\includegraphics[height=0.5em]{A2A8BBD2-B829-4BF8-8C8C-83DCD1611AB3}} & {\includegraphics[height=0.5em]{357E293C-7ACB-4120-847D-6BB7CD6832F8}}
\end{array} \\
&\\
\begin{array}{c|ccc}
{\includegraphics[height=0.5em]{18917130-74D6-44B0-A82A-A34D30ED80C2}} & {\includegraphics[height=0.5em]{5D4DC448-F726-4636-AD48-C5CA5938FE92}} & {\includegraphics[height=0.5em]{CC6837CF-A9C0-480A-84AE-DB0C9D81A17D}} & {\includegraphics[height=0.5em]{5660D13A-A089-4EFE-896A-DDC13CC322C3}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{7689BC0B-F451-489C-8D19-1C7652849232}} & {\includegraphics[height=0.5em]{17289437-9566-4DFB-8B6C-F7CDDFB852BF}} & {\includegraphics[height=0.5em]{EA48283B-C14C-4F40-8572-67E6D861A8E4}} & {\includegraphics[height=0.5em]{562C7E4B-DD1D-4DD3-A1E9-D295C6DB2EAB}} \\
{\includegraphics[height=0.5em]{E0C9AD68-F88A-4F6F-A0D0-1532412057C7}} & {\includegraphics[height=0.5em]{D56D288E-A237-4B0F-B179-2A44F33C5237}} & {\includegraphics[height=0.5em]{A1D6111C-813F-4E4F-900C-668EDD53E83E}} & {\includegraphics[height=0.5em]{DE70E17D-14A8-4C2E-A572-D601B96C57E3}} \\
{\includegraphics[height=0.5em]{6D0F048A-0D74-4D02-8839-7FBB11ED76B0}} & {\includegraphics[height=0.5em]{1C1BF965-2B09-46AD-B031-4E29C5036FD9}} & {\includegraphics[height=0.5em]{4D565C7B-F94B-4F77-93D6-BD891B285E80}} & {\includegraphics[height=0.5em]{AD45D957-AF0B-45B7-903F-36F296ADD847}}
\end{array}
&
\begin{array}{c|c}
{\includegraphics[height=0.5em]{DAB1D27A-06B6-496B-AB9C-25B01A83ABC4}} & & & \\[0.1em]\hline
{\includegraphics[height=0.5em]{076C6047-C8B2-4CED-AFE3-DB05362D9158}} & {\includegraphics[height=0.5em]{ABD8991E-9A99-4A19-B4CB-5090CC477036}} \\
{\includegraphics[height=0.5em]{FD0342CD-6D2E-45F1-B307-1257F0CD9B20}} & {\includegraphics[height=0.5em]{D949F501-0BE5-4D1F-B8BB-7EBA35C37715}} \\
{\includegraphics[height=0.5em]{D85066DF-C0F9-4DE7-8E74-EA142005FE8F}} & {\includegraphics[height=0.5em]{1F7757D8-FD8F-4D96-877B-512332D40D3F}}
\end{array}
\end{array}$ Equivalence ⟷ is deﬁned as follows, and contrasted with equality: $\begin{array}{c|ccc}
{\includegraphics[height=0.5em]{E27ECA54-CF65-4D48-8061-A10EA619706E}} & {\includegraphics[height=0.5em]{5F8D6CD7-ABF8-4177-AFF6-B6315AA99C6C}} & {\includegraphics[height=0.5em]{33E12C71-8F0E-479B-A4D8-BE879C9ECA96}} & {\includegraphics[height=0.5em]{15A05350-CA00-4BFA-AD6C-3133AE87AE63}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{965E7EF5-AA40-44AE-A16D-F7948D5132AB}} & {\includegraphics[height=0.5em]{02EBF999-1803-4D5A-8C28-BFE4C9D40451}} & {\includegraphics[height=0.5em]{BA3D940E-547A-481B-860B-4E734E4B6289}} & {\includegraphics[height=0.5em]{70C5C929-4684-4463-9C48-2B08AC320E8A}} \\
{\includegraphics[height=0.5em]{2374B8F9-ACCF-4775-A08B-E69DD6C4B6F8}} & {\includegraphics[height=0.5em]{FB2FB18C-1F4D-4E6A-AEA0-A18BDA813EB4}} & {\includegraphics[height=0.5em]{3A46BD68-E9C5-4881-B5E2-CEE2D7A55313}} & {\includegraphics[height=0.5em]{90FBC8E5-39F8-4357-8159-434247989712}} \\
{\includegraphics[height=0.5em]{B52C24FF-68A8-4AF5-A945-35E75C15008F}} & {\includegraphics[height=0.5em]{FCDD03A6-A1F5-482F-8E5D-10CAAA1EB920}} & {\includegraphics[height=0.5em]{B0A8090E-4E9C-4F15-AF80-76673F1158BE}} & {\includegraphics[height=0.5em]{4F2ADF8B-A3EB-4472-BC40-898000D714BA}}
\end{array}
\quad
\begin{array}{c|ccc}
{\includegraphics[height=0.5em]{1B51AAA0-A3D4-485B-91C2-E34126F0B269}} & {\includegraphics[height=0.5em]{4A0B4036-8795-4AF9-8744-45C903E3B394}} & {\includegraphics[height=0.5em]{4EDB4F7C-4814-473C-8503-AE4700BA322F}} & {\includegraphics[height=0.5em]{970D16A0-FA8C-44D4-A0ED-1B740ADE4E0F}} \\[0.1em]\hline
{\includegraphics[height=0.5em]{18DBD23E-8928-4461-BA33-2A5056291BCC}} & {\includegraphics[height=0.5em]{83F6AFB3-7312-45D2-8259-BC9728E43315}} & {\includegraphics[height=0.5em]{6D1CFB93-65ED-4143-8EF3-C46E0134F43E}} & {\includegraphics[height=0.5em]{3D483F29-5267-4AEA-BFCA-C03F33FA793B}} \\
{\includegraphics[height=0.5em]{D169336D-C866-4459-A2A0-8B964B3E426F}} & {\includegraphics[height=0.5em]{4B871DB3-60FD-4B84-BA0A-E7E4CDCC7D45}} & {\includegraphics[height=0.5em]{279DC582-1B73-4BF1-9753-F95BB5386DBE}} & {\includegraphics[height=0.5em]{7B735C7F-2743-43CB-A79A-3F3C26F5CCF7}} \\
{\includegraphics[height=0.5em]{9F76E204-E09F-423F-9858-CA5978EB052B}} & {\includegraphics[height=0.5em]{63090107-EEC4-459E-BB95-087F3144B4EB}} & {\includegraphics[height=0.5em]{8A24B929-E993-461A-8256-4C22B7E9B5F7}} & {\includegraphics[height=0.5em]{AE8448E5-8DBF-4AC4-B3C3-785A400E68A1}}
\end{array}$

Similarly, quantiﬁers ∀ and ∃ work on *partial predicates*. They both have type

(α : Type) → (α ↪ ℙ) → ℙ

Assume P : α ↪ ℙ. We deﬁne ∀ and ∃ as follows:

- If for all x : α we have P x = true then (∀ x : α. P x) = true, otherwise (∀ x : α. P x) = false.
- If there is x : α such that P x = true then (∃ x : α. P x) = true, otherwise (∃ x : α. P x) = false.

Furthermore, the Hilbert choice operator ε has type

(α : Type) → (α ↪ ℙ) ↪ α

and we deﬁne it such that if there is x : α with P x = true, then P (ε x : α. P x) = true, otherwise (ε x : α. P x) = nil.

Kerber and Kohlhase [12] argue that the formula

∀ x y z : ℝ. z = x / y ⟶ z ⋅ y = x

should not be a theorem because y = 0 provides a counter example. I don’t agree. The assumption is that for real numbers x,y and z we have z = x / y. This also implies that y cannot be zero, because otherwise x / y would not be a real number.

In Farmer’s approach as well as in Practal above formula is a theorem, albeit for a different reason. While Farmer’s approach and Practal’s approach are closely related, they are not the same. Consider again the formula 1/0 < 2. In Farmer’s approach (1/0 < 2) = false, but in Practal (1/0 < 2) = nil holds. A bigger deviation can be observed for the formula 1/0 = 2/0. This formula is false in Farmer’s approach because the binary predicate = is applied to undeﬁned terms. In Practal this formula is a theorem, because 1/0 = nil and 2/0 = nil both hold.

One of the advantages of nil being specially treated in some situations, but otherwise being a normal value, is that users of Practal can customize undeﬁnedness and optionality for their own particular use case. For example, for deﬁning partial recursive functions you might want to deﬁne and use the logical operators from strong Kleene logic [11] as well.

There are various ways to deﬁne new types:

- via structure
- via typealias
- via typedef

For example, in the category use case a new type called Category is introduced. Each instance of the type can be thought of as a record with the corresponding ﬁelds, fulﬁlling the given axioms, and tagged with the name Category to distinguish it from all other records.

Another way to introduce a new type is via typealias, but the newly introduced type is not really new, but just an abbreviation for the original type. For example, we have

∀ A B : Type. (A ↪ B ) = (A → (B ∪ Nil))

A third way of introducing a new type is via typedef. We could have also introduced the type of partial functions as follows:

typedef A ↪ B = A → (B ∪ Nil)

The difference to the typealias version is that this type of partial functions consists of entirely new elements. A way to think of the elements of the new type conceptually is as pairs $(\text{tag}, f)$ where $\text{tag}$ is Partial-Function, and $f$ has the type A → (B ∪ Nil). In particular, the following inequality would then be true:

∀ A B : Type. (A ↪ B) ≠ (A → (B ∪ Nil))

A most common tool employed by mathematicians is the forming of *quotients*, i.e. forming a new type from an existing type by identifying elements based on an equivalence relation. Also, often when creating quotients one will want to inject existing types into it. We can accommodate both by augmenting a typedef with identify clauses, for example when creating the rational numbers ℚ from the integers ℤ:

typedef ℚ = ℤ ⨯ (ℤ \ {0}) identify (a, b) in ℚ with (c, d) in ℚ where a ⋅ d = c ⋅ b identify z in ℤ with (z, 1) in ℚ

This results in the rational numbers ℚ such that ℤ ≤ ℚ holds, i.e. the integers form a subtype of the rational numbers. We can leave out the in ℚ phrases for the sake of more concise notation and write:

typedef ℚ = ℤ ⨯ (ℤ \ {0}) identify (a, b) with (c, d) where a ⋅ d = c ⋅ b identify z in ℤ with (z, 1)

Similarly, ℤ could have been constructed from ℕ via

typedef ℤ = ℕ ⨯ ℕ identify (a, b) with (c, d) where a + d = c + b identify n in ℕ with (n, 0)

and thus both ℕ ≤ ℤ and ℕ ≤ ℚ would hold.

One can see now that typealias is really just a special case of typedef. Instead of

typealias B = A

one could also write

typedef B = A identify a in A with a in B

When asked what the foundation of mathematics is, most mathematicians will answer "set theory". But it is clear that most mathematicians will not reduce the math they do to set theory, and that concepts from orthodox set theory like ordinal numbers do not play a role in their practice.

In my opinion, types as proposed for Practal are closer to mathematical practice than normal set theory. Practal types are really sets in (not much of a) disguise. The type of sets with elements from A can be modelled often satisfactorily by

typealias Set (A : Type) = A → ℙ

On the other hand, if a mathematician wants to use full Zermelo-Fraenkel set theory, then they should be able to do so in Practal. A simple way to achieve this is to declare a structure that captures the axioms of ZF set theory:

structure ZF = type Set let ∈ : Set → Set → ℙ let ∅ : Set let Un : Set → Set let Pow : Set → Set let Repl : Set → (Set → Set) → Set let Sep : Set → (Set → ℙ) → Set let Inf : Set axiom Empty: ∀ x : Set. ¬ (x ∈ ∅) axiom Extensionality: ∀ x y : Set. (x = y) = (∀ z : Set. (z ∈ x) = (z ∈ y)) axiom Union: ∀ z x : Set. (z ∈ Un x) = (∃ y : Set. z ∈ y ∧ y ∈ x) axiom Power: ∀ x y : Set. (y ∈ Pow x) = (∀ z : Set. z ∈ y ⟶ z ∈ x) axiom Replacement: ∀ f : Set → Set. ∀ y X : Set. y ∈ (Repl X f) = (∃ x : Set. x ∈ X ∧ y = f x) axiom Separation: ∀ f : Set → ℙ. ∀ x X : Set. x ∈ (Sep X f) = (x ∈ X ∧ f x) axiom Regularity: ∀ X : Set. X ≠ ∅ ⟶ (∃ x : Set. x ∈ X ∧ (∀ y : Set. y ∈ x ⟶ ¬ (y ∈ X))) def UPair(x : Set, y : Set) = Repl (Pow (Pow ∅)) (λ z. if z = ∅ then x else y) def Singleton(x : Set) = UPair(x, x) def union(x : Set, y : Set) = Un (UPair(x, y)) def Suc(x : Set) = union x (Singleton x) axiom Infinity: ∅ ∈ Inf ∧ (∀ x : Set. x ∈ Inf ⟶ Suc x ∈ Inf) end

We then presume the existence of an instance of this structure:

let 𝕌 : ZF

This approach has been used before to work with ZF set theory in higher-order logic. A discussion can be found in my paper about formalizing Partizan Games [13]. More recently, the approach has been used for formalizing ordinal partition relations [14]. Also, one doesn’t need to stop with Zermelo-Fraenkel set theory, but could add further axioms, for example for Grothendieck universes [15].

A set s : 𝕌.Set can be viewed as a type via

{ x : 𝕌.Set | x ∈ s }

and is therefore tightly integrated with other formalizations in Practal. For example, one should be able to prove in Practal that the subsets of a ZF set together with their set-theoretic functions form a category as deﬁned via the Category structure.

I believe that this way of approaching normal set theory is superior to solutions internal to set theory, like for example the one based on *urelements* I outlined in a mathoverﬂow post. But both approaches have a lot in common, so it might make sense to combine them somehow.

Harrison makes an emphatic case for the use of sets in ITP instead of types. I think Practal types provide the ﬂexibility that Harrison calls for. In particular, it is not necessary to decide between formalizing a concept as a predicate or as a type, because in Practal, a predicate can also be used as a type without friction.

Hales has made an argument for the use of controlled natural language in mathematics. I fully agree with it. There will be a controlled natural language for Practal as its topmost user interaction layer.

I just recently learnt about *paraconsistent logics* [16], so my excitement about it is fresh and untainted. The idea behind paraconsistent logics is to prevent the phenomenon of *explosion* that occurs in classical logic when both H and ¬H can be proven for some proposition H. Because in classical logic H and ¬H together imply false, any proposition G can now be proven although it might have nothing to do with H.

I don’t know whether supporting paraconsistency would make using Practal awkward. It is intriguing that paraconsistency can be considered a dual notion to intuitionism, which is very popular in ITP circles.

What I ﬁnd interesting about supporting paraconsistency is that it might make playing around with possibly *inconsistent objects* possible without infecting otherwise supposedly consistent theories. But maybe providing a "Practal playground" where users can assume arbitrary axioms without endangering the consistency of other formalizations is an easier solution for this.

Finally, what if the features of Practal that I have outlined cannot be implemented in a consistent way? There are many gotchas in logic, like Russell’s paradox or Girard’s paradox [17]. I don’t believe that this is the case for Practal, *but if indeed a practical logic as envisioned cannot be consistent*, maybe paraconsistency is the solution.

Considering the most impressive strides that artiﬁcial intelligence has taken in the last decade or so, Practal is being designed under the assumption that powerful automation can be achieved. This assumption has already been partially validated by projects like Isabelle/Sledgehammer that are based on classical automated theorem proving. Current AI projects like Github Copilot only provide more evidence to support this assumption. In particular, type checking does not have to be decidable; it just has to be certiﬁable. The assumption of strong automation being achievable frees us from many design constraints that would hinder us in making Practal as useful and pleasant to use as possible.

About seventeen years ago I was told that asking questions is easy, but providing answers is diﬃcult. That is true. What is also true is that if you don’t ask the right question, then the answer does not really matter.

When it comes to Practal, I believe the right question is the following: *How do we build an ITP system that is a true bicycle for the mathematical mind?* Achieving this goal would mean mathematically inclined people using Practal willingly and happily; because it helps them to think better and faster, instead of slowing them down and hindering their creativity.

If you have any comments, questions, and/or want to share your ideas for Practal, please visit Practal’s discussion forum!

[8](1998). Subtypes for specifications: predicate subtyping in PVS, https://doi.org/10.1109/32.713327.

[10](2004). Formalizing Undefinedness Arising in Calculus, https://doi.org/10.1007/978-3-540-25984-8_35.

[11](1952). Introduction to Metamathematics, §64: The 3-valued logic, https://www.elsevier.com/books/introduction-to-metamathematics/kleene/978-0-7204-2103-3.

[12](1994). A mechanization of strong Kleene logic for partial functions, https://doi.org/10.1007/3-540-58156-1_26.

[14](2020). Formalising Ordinal Partition Relations Using Isabelle/HOL, https://doi.org/10.17863/CAM.70018.

[15](2019). Higher-Order Tarski Grothendieck as a Foundation for Formal Proof, https://doi.org/10.4230/LIPIcs.ITP.2019.9.

[16](2016). Paraconsistent Logic: Consistency, Contradiction and Negation, https://doi.org/10.1007/978-3-319-33205-5.