Why 2 + 2 = 4 is a type, not a boolean

Lean treats every logical claim as a type you must build a value for, and that one shift lets you pass proven facts around a program.

20 cards · 5m · tap to begin

From · · 5m

Why 2 + 2 = 4 is a type, not a boolean

Lean treats every logical claim as a type you must build a value for, and that one shift lets you pass proven facts around a program.

In brief

Lean treats every logical claim as a type you must build a value for, and that one shift lets you pass proven facts around a program. A proposition is a type and a proof is a value of that type, so verifying math becomes typechecking, and established facts can travel through your code like data. Originally reported by…

Start with a simple question

What is the type of 2 + 2 = 4? In almost every language the answer is boring. Lean answers differently, and the difference changes what a program can promise.

TypeScript collapses the question

Hover in TypeScript playground: question2 is a boolean

Write 2 + 2 === 4 and TypeScript hands back a boolean before you can blink. The claim itself disappears and only the verdict survives. Every logical expression lands in that same single type.

Lean gives you a Prop

Hover in Lean playground showing question2 is of type Prop

In Lean, 2 + 2 = 4 has type Prop, short for logical proposition. So does 2 + 2 = 5. Being wrong does not change what type it is.

Claims stay claims

A Lean proposition never collapses into true or false. It stays a sentence you can name, hold onto, and hand to other code.

“A proposition remains a proposition”

So compute it? No

You cannot calculate your way to truth here. Adding up 1 + 1/2 + 1/4 + 1/8 and onward to show it equals 2 would need infinite time and memory. Lean makes you argue instead.

“You compute it! Just kidding.”

A proposition is also a type

Here is the twist. 2 = 2 is a value of type Prop, and it is itself a type. A proof is simply any value of that type.

by rfl builds the proof

def proof1 : 2 = 2 := by rfl typechecks. The tactic returns something whose type is literally 2 = 2, which in turn sits under Prop. A two storey tower TypeScript cannot build.

Proving equals typechecking

If the value fits the type, the claim is established. Nothing executes. A tiny kernel just checks that the pieces line up.

“Verifying any mathematical result in Lean is nothing more than typechecking.”

The lonely type

No one can produce a value of type 2 + 2 = 5, barring a sorry or a bad axiom. That type sits there with no inhabitants at all.

Note the Not

Empty is not the same as false. Maybe you were just unlucky. So you prove the negation: Not (2 + 2 = 5) is its own proposition, and by decide supplies a value for it.

False means uninhabited

Once the negation typechecks, nothing can ever inhabit 2 + 2 = 5. It behaves like TypeScript's never, a type whose value you cannot produce without cheating.

“If the proof typechecks, the argument must be correct.”

All proofs are equal

2 + 2 = 4 can be proved by rfl, by decide, or with Mathlib's two_add_two_eq_four. Once checked, Lean treats all three as the same thing.

“In Lean, all proofs of the same proposition are considered equal”

What booleans throw away

A boolean answers the question and forgets it was asked. A TypeScript function guarding a range from 0 to 1 can only throw at runtime, on every single call, forever.

“it erases the knowledge of which facts have been established”

Pass facts as arguments

In Lean the function takes x, a proof that x is at least 0, and a proof that x is at most 1. Call it with 1.2 and the typechecker stops you before anything runs.

“Now anyone who calls this function will also have to supply these two proofs.”

Beyond number literals

Feed it (sin a) squared and norm_num gives up, because a is unknown. You still know things though. A square is non negative, and sine never leaves the band from -1 to 1.

Ask Lean to find it

Lean suggests exact sq_nonneg (Real.sin a)

Write apply? and Lean searches the library. It surfaces sq_nonneg, a proof of anything shaped like foo squared is at least 0, ready to apply to sin a.

The second hole closes

Lean suggests exact sin_sq_le_one a

Ask again and out comes sin_sq_le_one, which proves sine squared is at most 1. Both stubs filled, the whole definition typechecks with no sorry left in it.

“Mathlib is just a bunch of open source proofs.”

Truths about uncomputable things

Real.sin cannot be calculated to infinite precision, so the function is marked noncomputable. You can still prove hard facts about it, and about pi, infinite series, and infinite sets.

Behind the by

Screenshot of Lean source code defining a = b

a = b turns out to be sugar for Eq a b, and Eq is defined in Lean itself as a type that doubles as a function call. Types are values here, so generics are just arguments.

“Yes, it's a function call that returns a type.”

One constructor, no escape

Eq has a single constructor, refl, and it can only ever build Eq a a. That is why Eq 2 3 has no inhabitants, and why 2 = 3 can never be proved. Go play the Natural Number Game.

“it's genuinely thrilling to pass facts around the program and to know they're true.”

What to remember

A proposition is a type and a proof is a value of that type, so verifying math becomes typechecking, and established facts can travel through your code like data.

Read the original on Overreacted

React

Sign in to react and comment.

Comments (0)

Life is short. Keep it sweet. Respect others' opinions and be kind!

    Recommended next

    More decks on lean and related topics.