Chapters

Dependent Types and Universes

Use values to express types and propositions more precisely.

17.1 Types can depend on values

An ordinary List(A) describes its element type A, but its type does not include its length. Dependent types can change shape according to a value. Tauto's a = b is already a proposition depending on the values a and b.

ch17-equal.taut
import std::Base

theorem equal_to_self(n: Nat): n = n {
  Refl
}

// The proposition depends on the supplied natural number.
✓ Check passed
✓ theorem equal_to_self : ∀ n: Nat. n = n

The theorem's specific result equality depends on its argument n. Unlike a function that merely returns Bool, type checking verifies evidence of the proposition.

17.2 Prop and Type

Prop is the world of propositions to be proved; Type is the world of data and types. Higher universes such as Type1 and Type2 are used when needed. You can also define types parameterized by a universe level.

ch17-ubox.taut
import std::Base

inductive UBox(u: Level, A: Type(u)): Type(u) {
  ubox(value: A): UBox(u, A)
}

theorem small_box(): UBox(0, Nat) {
  ubox(0, Nat, 3)
}

// Instantiate a universe-polymorphic box at numeric universe level zero.
✓ Check passed
✓ UBox
✓ theorem small_box : UBox@0(Nat)
ok      UBox@0
ok      small_box

u: Level is a universe-level parameter, used with a numeric level. Universe polymorphism has restrictions; do not assume unrestricted inference of free symbolic levels.

17.3 Stronger types express stronger specifications

The more conditions a type expresses, the more errors checking can exclude. However, complex types also take more effort to read and understand. When learning Tauto, start by stating the intended property as a simple proposition, then prove only the properties you need.

Exercise 17.1: Why are n = n and n = 0 very different claims?