@startuml type-hierarchy !theme plain title Type System: Stratified Universes & Types as Relations package "Universe Stratification" { class "Universe₀" as U0 { Base values Examples: 3, -5, 3.14, true, "hello" The set of all runtime values } class "Universe₁" as U1 { Type relations (classify values) Examples: natural, integer, real, boolean Each type is a relation over Universe₀ Type relations are infinite relations } class "Universe₂" as U2 { Type of type relations The classifier of type relations Prevents self-reference paradoxes } class "Universe₃" as U3 { Meta-type level Type : Universe₂ : Universe₃ } U0 : Universe₁ U1 : Universe₂ U2 : Universe₃ U3 : Universe₄ note right of U1 **Stratification prevents Russell's Paradox** Type relations live in Universe₁ and classify values in Universe₀. A type cannot contain itself. natural : Universe₁ 3 ∈ natural (3 ∈ Universe₀) But: natural ∉ natural ✗ (universe mismatch) end note } package "Supertypes (Universe₁)" { class Number { Membership: number[X] where X : Universe₀ Definition: Union of all numeric types number[X] :- natural[X]; integer[X]; rational[X]; real[X]. Allows polymorphism over numeric types Universe level: Universe₁ } class Scalar { Membership: scalar[X] where X : Universe₀ Definition: Atomic (non-composite) values scalar[X] :- number[X]; boolean[X]; string[X]. Universe level: Universe₁ } } package "Numeric Type Relations (Universe₁)" { class Naturals { Membership: natural[X] where X : Universe₀ Criteria: - X is erlang:integer() - X >= 0 Cardinality: aleph_zero Generator: 0, 1, 2, 3, ... Universe level: Universe₁ } class Integers { Membership: integer[X] where X : Universe₀ Criteria: - X is erlang:integer() Cardinality: aleph_zero Generator: 0, 1, -1, 2, -2, ... Universe level: Universe₁ } class Rationals { Membership: rational[X] where X : Universe₀ Criteria: - X is (P, Q) - integer[P], integer[Q] - Q ≠ 0 Cardinality: aleph_zero Generator: Stern-Brocot tree Universe level: Universe₁ } class Reals { Membership: real[X] where X : Universe₀ Criteria: - X is erlang:float() Cardinality: continuum Generator: IEEE 754 floats Universe level: Universe₁ } } package "Other Primitive Types (Universe₁)" { class Strings { Membership: string[X] where X : Universe₀ Criteria: - X is erlang:string() Cardinality: aleph_zero Ordering: by length, then lexicographic Universe level: Universe₁ } class Booleans { Membership: boolean[X] where X : Universe₀ Criteria: - X is erlang:boolean() - X ∈ {true, false} Cardinality: 2 Universe level: Universe₁ } } package "Constrained Type Relations (Universe₁)" { class PositiveIntegers { Definition: positive_int[X] where X : Universe₀ Criteria: - integer[X] - X > 0 Relation: positive_int ⊆ integer Universe level: Universe₁ } class BoundedInt { Definition: bounded_int[X, Min, Max] where X : Universe₀ Criteria: - integer[X] - Min ≤ X ≤ Max Relation: bounded_int ⊆ integer Universe level: Universe₁ } class NonEmptyStrings { Definition: non_empty_string[X] where X : Universe₀ Criteria: - string[X] - length(X) > 0 Relation: non_empty_string ⊆ string Universe level: Universe₁ } } package "Composite Type Relations (Universe₁)" { class Complex { Definition (Karuta-style): complex[X] where X : Universe₀ complex[X] :- X is (A, B), real[A], real[B]. Interpretation: - (A, B) where A is real part - B is imaginary part Relation: complex ⊆ real × real Universe level: Universe₁ } class Employee { Definition: employee[X] where X : Universe₀ employee[X] :- X is (Name, Age, Salary), non_empty_string[Name], positive_int[Age], positive_int[Salary]. Relation: employee ⊆ string × ℕ⁺ × ℕ⁺ Universe level: Universe₁ } } ' Universe stratification relationships U1 --> U0 : classifies values in U2 --> U1 : types type relations U3 --> U2 : meta-level ' All type relations live in Universe₁ U1 ..> Number : contains U1 ..> Naturals : contains U1 ..> Integers : contains U1 ..> Rationals : contains U1 ..> Reals : contains U1 ..> Booleans : contains U1 ..> Strings : contains U1 ..> Scalar : contains ' Type relation hierarchy (within Universe₁) Number <|-- Naturals : ⊇ Number <|-- Integers : ⊇ Number <|-- Rationals : ⊇ Number <|-- Reals : ⊇ Number <|-- Scalar : ⊇ Booleans <|-- Scalar : ⊇ Strings <|-- Scalar : ⊇ ' Subset relations among numeric types Naturals .up.|> Integers : ⊆ Integers .up.|> Rationals : ⊆ Rationals .up.|> Reals : ⊆ ' Constrained types Integers .down.|> PositiveIntegers : ⊇ Integers .down.|> BoundedInt : ⊇ Strings .down.|> NonEmptyStrings : ⊇ ' Composite types (also in Universe₁) Number .down.|> Complex : number × number Complex : (view: pair of numbers) Scalar .down.|> Employee : scalar × scalar × scalar Employee : (view: string × nat × nat) note right of Complex **Views as Type Relations:** Types can be defined as relational views over other type relations. Example using supertype: complex[C] :- C is (R, I), number[R], number[I]. Or more specifically: complex[C] :- C is (R, I), real[R], real[I]. Views can use supertypes for flexibility! All views live in Universe₁. end note note left of Number **Core Principle:** Every type is a relation Type checking = membership checking in relations T1 <: T2 iff T1 ⊆ T2 (subset relation) **Supertypes enable polymorphism:** A function can accept number[X] and work with naturals, integers, rationals, or reals. **Universe Levels:** All type relations: Universe₁ All values: Universe₀ Type of types: Universe₂ **Erlang Type Mapping:** natural → integer() + (≥ 0) integer → integer() rational → {integer(), integer()} real → float() string → string() boolean → boolean() end note note bottom of U0 **Avoiding Russell's Paradox:** Like F*, Domino uses predicative universe stratification. The key invariant: Type u#i : Type u#(i+1) In Domino: - Values (3, "hello", true) : Universe₀ - Type relations (natural, string) : Universe₁ - Type : Universe₂ This prevents: natural ∈ natural (universe mismatch!) A type relation cannot be a member of itself. All type relations classify values in Universe₀ but exist at Universe₁. end note @enduml