logicaffeine_kernel/term.rs
1//! Unified term representation for the Calculus of Constructions.
2//!
3//! In CoC, there is no distinction between terms and types.
4//! Everything is a Term in an infinite hierarchy of universes.
5
6use std::fmt;
7
8/// Primitive literal values.
9///
10/// These are opaque values that compute via hardware ALU, not recursion.
11#[derive(Debug, Clone, PartialEq)]
12pub enum Literal {
13 /// 64-bit signed integer
14 Int(i64),
15 /// 64-bit floating point
16 Float(f64),
17 /// UTF-8 string
18 Text(String),
19}
20
21impl Eq for Literal {}
22
23impl fmt::Display for Literal {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Literal::Int(n) => write!(f, "{}", n),
27 Literal::Float(x) => write!(f, "{}", x),
28 Literal::Text(s) => write!(f, "{:?}", s),
29 }
30 }
31}
32
33/// Universe levels in the type hierarchy.
34///
35/// The hierarchy is: Prop : Type 1 : Type 2 : Type 3 : ...
36///
37/// - `Prop` is the universe of propositions (proof-irrelevant in full CIC)
38/// - `Type(n)` is the universe of types at level n
39#[derive(Debug, Clone, PartialEq, Eq)]
40pub enum Universe {
41 /// Prop - the universe of propositions
42 Prop,
43 /// Type n - the universe of types at level n
44 Type(u32),
45}
46
47impl Universe {
48 /// Get the successor universe: Type n → Type (n+1)
49 pub fn succ(&self) -> Universe {
50 match self {
51 Universe::Prop => Universe::Type(1),
52 Universe::Type(n) => Universe::Type(n + 1),
53 }
54 }
55
56 /// Get the maximum of two universes (for Pi type formation)
57 pub fn max(&self, other: &Universe) -> Universe {
58 match (self, other) {
59 (Universe::Prop, u) | (u, Universe::Prop) => u.clone(),
60 (Universe::Type(a), Universe::Type(b)) => Universe::Type((*a).max(*b)),
61 }
62 }
63
64 /// Check if this universe is a subtype of another (cumulativity).
65 ///
66 /// Subtyping rules:
67 /// - Prop ≤ Type(i) for all i
68 /// - Type(i) ≤ Type(j) if i ≤ j
69 /// - Type(i) is NOT ≤ Prop
70 pub fn is_subtype_of(&self, other: &Universe) -> bool {
71 match (self, other) {
72 // Prop ≤ anything (Prop ≤ Prop, Prop ≤ Type(i))
73 (Universe::Prop, _) => true,
74 // Type(i) ≤ Type(j) if i ≤ j
75 (Universe::Type(i), Universe::Type(j)) => i <= j,
76 // Type(i) is NOT ≤ Prop
77 (Universe::Type(_), Universe::Prop) => false,
78 }
79 }
80}
81
82/// Unified term representation.
83///
84/// Every expression in CoC is a Term:
85/// - `Sort(u)` - universes (Type 0, Type 1, Prop)
86/// - `Var(x)` - variables
87/// - `Pi` - dependent function types: Π(x:A). B
88/// - `Lambda` - functions: λ(x:A). t
89/// - `App` - application: f x
90#[derive(Debug, Clone, PartialEq, Eq)]
91pub enum Term {
92 /// Universe: Type n or Prop
93 Sort(Universe),
94
95 /// Local variable reference (bound by λ or Π)
96 Var(String),
97
98 /// Global definition (inductive type or constructor)
99 Global(String),
100
101 /// Dependent function type: Π(x:A). B
102 ///
103 /// When B doesn't mention x, this is just A → B.
104 /// When B mentions x, this is a dependent type.
105 Pi {
106 param: String,
107 param_type: Box<Term>,
108 body_type: Box<Term>,
109 },
110
111 /// Lambda abstraction: λ(x:A). t
112 Lambda {
113 param: String,
114 param_type: Box<Term>,
115 body: Box<Term>,
116 },
117
118 /// Application: f x
119 App(Box<Term>, Box<Term>),
120
121 /// Pattern matching on inductive types.
122 ///
123 /// `match discriminant return motive with cases`
124 ///
125 /// - discriminant: the term being matched (must have inductive type)
126 /// - motive: λx:I. T — describes the return type
127 /// - cases: one case per constructor, in definition order
128 Match {
129 discriminant: Box<Term>,
130 motive: Box<Term>,
131 cases: Vec<Term>,
132 },
133
134 /// Fixpoint (recursive function).
135 ///
136 /// `fix name. body` binds `name` to itself within `body`.
137 /// Used for recursive definitions like addition.
138 Fix {
139 /// Name for self-reference within the body
140 name: String,
141 /// The body of the fixpoint (typically a lambda)
142 body: Box<Term>,
143 },
144
145 /// Primitive literal value.
146 ///
147 /// Hardware-native values like i64, f64, String.
148 /// These compute via CPU ALU, not recursion.
149 Lit(Literal),
150
151 /// Hole (implicit argument).
152 ///
153 /// Represents an argument that should be inferred by the type checker.
154 /// Used in Literate syntax like `X equals Y` where the type of X/Y is implicit.
155 Hole,
156}
157
158impl fmt::Display for Universe {
159 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160 match self {
161 Universe::Prop => write!(f, "Prop"),
162 Universe::Type(n) => write!(f, "Type{}", n),
163 }
164 }
165}
166
167impl fmt::Display for Term {
168 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169 match self {
170 Term::Sort(u) => write!(f, "{}", u),
171 Term::Var(name) => write!(f, "{}", name),
172 Term::Global(name) => write!(f, "{}", name),
173 Term::Pi {
174 param,
175 param_type,
176 body_type,
177 } => {
178 // Use arrow notation for non-dependent functions (param = "_")
179 if param == "_" {
180 write!(f, "{} -> {}", param_type, body_type)
181 } else {
182 write!(f, "Π({}:{}). {}", param, param_type, body_type)
183 }
184 }
185 Term::Lambda {
186 param,
187 param_type,
188 body,
189 } => {
190 write!(f, "λ({}:{}). {}", param, param_type, body)
191 }
192 Term::App(func, arg) => {
193 // Arrow types (Pi with _) need inner parens when used as args
194 let arg_needs_inner_parens =
195 matches!(arg.as_ref(), Term::Pi { param, .. } if param == "_");
196
197 if arg_needs_inner_parens {
198 write!(f, "({} ({}))", func, arg)
199 } else {
200 write!(f, "({} {})", func, arg)
201 }
202 }
203 Term::Match {
204 discriminant,
205 motive,
206 cases,
207 } => {
208 write!(f, "match {} return {} with ", discriminant, motive)?;
209 for (i, case) in cases.iter().enumerate() {
210 if i > 0 {
211 write!(f, " | ")?;
212 }
213 write!(f, "{}", case)?;
214 }
215 Ok(())
216 }
217 Term::Fix { name, body } => {
218 write!(f, "fix {}. {}", name, body)
219 }
220 Term::Lit(lit) => {
221 write!(f, "{}", lit)
222 }
223 Term::Hole => {
224 write!(f, "_")
225 }
226 }
227 }
228}