Skip to main content

logicaffeine_kernel/
prelude.rs

1//! Standard Library for the Kernel.
2//!
3//! Defines fundamental types and logical connectives:
4//! - Entity: domain of individuals (for FOL)
5//! - Nat: natural numbers
6//! - True, False: propositional constants
7//! - Eq: propositional equality
8//! - And, Or: logical connectives
9
10use crate::context::Context;
11use crate::term::{Term, Universe};
12
13/// Standard library definitions.
14pub struct StandardLibrary;
15
16impl StandardLibrary {
17    /// Register all standard library definitions in the context.
18    pub fn register(ctx: &mut Context) {
19        Self::register_entity(ctx);
20        Self::register_nat(ctx);
21        Self::register_bool(ctx);
22        Self::register_tlist(ctx);
23        Self::register_true(ctx);
24        Self::register_false(ctx);
25        Self::register_not(ctx);
26        Self::register_eq(ctx);
27        Self::register_and(ctx);
28        Self::register_or(ctx);
29        Self::register_ex(ctx);
30        Self::register_primitives(ctx);
31        Self::register_reflection(ctx);
32    }
33
34    /// Primitive types and operations.
35    ///
36    /// Int : Type 0 (64-bit signed integer)
37    /// Float : Type 0 (64-bit floating point)
38    /// Text : Type 0 (UTF-8 string)
39    /// Duration : Type 0 (nanoseconds, i64 - physical time)
40    /// Date : Type 0 (days since epoch, i32 - calendar date)
41    /// Moment : Type 0 (nanoseconds since epoch, i64 - instant in UTC)
42    ///
43    /// add, sub, mul, div, mod : Int -> Int -> Int
44    fn register_primitives(ctx: &mut Context) {
45        // Opaque types (no constructors, cannot be pattern-matched)
46        ctx.add_inductive("Int", Term::Sort(Universe::Type(0)));
47        ctx.add_inductive("Float", Term::Sort(Universe::Type(0)));
48        ctx.add_inductive("Text", Term::Sort(Universe::Type(0)));
49
50        // Temporal types (opaque, no constructors)
51        ctx.add_inductive("Duration", Term::Sort(Universe::Type(0)));
52        ctx.add_inductive("Date", Term::Sort(Universe::Type(0)));
53        ctx.add_inductive("Moment", Term::Sort(Universe::Type(0)));
54
55        let int = Term::Global("Int".to_string());
56
57        // Binary Int -> Int -> Int type
58        let bin_int_type = Term::Pi {
59            param: "_".to_string(),
60            param_type: Box::new(int.clone()),
61            body_type: Box::new(Term::Pi {
62                param: "_".to_string(),
63                param_type: Box::new(int.clone()),
64                body_type: Box::new(int.clone()),
65            }),
66        };
67
68        // Register arithmetic builtins as declarations (axioms with computational behavior)
69        ctx.add_declaration("add", bin_int_type.clone());
70        ctx.add_declaration("sub", bin_int_type.clone());
71        ctx.add_declaration("mul", bin_int_type.clone());
72        ctx.add_declaration("div", bin_int_type.clone());
73        ctx.add_declaration("mod", bin_int_type);
74
75        // Temporal operations
76        let duration = Term::Global("Duration".to_string());
77        let date = Term::Global("Date".to_string());
78        let moment = Term::Global("Moment".to_string());
79        let bool_type = Term::Global("Bool".to_string());
80
81        // Duration -> Duration -> Duration
82        let bin_duration_type = Term::Pi {
83            param: "_".to_string(),
84            param_type: Box::new(duration.clone()),
85            body_type: Box::new(Term::Pi {
86                param: "_".to_string(),
87                param_type: Box::new(duration.clone()),
88                body_type: Box::new(duration.clone()),
89            }),
90        };
91
92        // Duration -> Int -> Duration
93        let duration_int_duration_type = Term::Pi {
94            param: "_".to_string(),
95            param_type: Box::new(duration.clone()),
96            body_type: Box::new(Term::Pi {
97                param: "_".to_string(),
98                param_type: Box::new(int.clone()),
99                body_type: Box::new(duration.clone()),
100            }),
101        };
102
103        // Duration arithmetic: add, sub, mul, div
104        ctx.add_declaration("add_duration", bin_duration_type.clone());
105        ctx.add_declaration("sub_duration", bin_duration_type.clone());
106        ctx.add_declaration("mul_duration", duration_int_duration_type.clone());
107        ctx.add_declaration("div_duration", duration_int_duration_type);
108
109        // Date -> Int -> Date (add days offset)
110        let date_int_date_type = Term::Pi {
111            param: "_".to_string(),
112            param_type: Box::new(date.clone()),
113            body_type: Box::new(Term::Pi {
114                param: "_".to_string(),
115                param_type: Box::new(int.clone()),
116                body_type: Box::new(date.clone()),
117            }),
118        };
119        ctx.add_declaration("date_add_days", date_int_date_type);
120
121        // Date -> Date -> Int (difference in days)
122        let date_date_int_type = Term::Pi {
123            param: "_".to_string(),
124            param_type: Box::new(date.clone()),
125            body_type: Box::new(Term::Pi {
126                param: "_".to_string(),
127                param_type: Box::new(date.clone()),
128                body_type: Box::new(int.clone()),
129            }),
130        };
131        ctx.add_declaration("date_sub_date", date_date_int_type);
132
133        // Moment -> Duration -> Moment
134        let moment_duration_moment_type = Term::Pi {
135            param: "_".to_string(),
136            param_type: Box::new(moment.clone()),
137            body_type: Box::new(Term::Pi {
138                param: "_".to_string(),
139                param_type: Box::new(duration.clone()),
140                body_type: Box::new(moment.clone()),
141            }),
142        };
143        ctx.add_declaration("moment_add_duration", moment_duration_moment_type);
144
145        // Moment -> Moment -> Duration
146        let moment_moment_duration_type = Term::Pi {
147            param: "_".to_string(),
148            param_type: Box::new(moment.clone()),
149            body_type: Box::new(Term::Pi {
150                param: "_".to_string(),
151                param_type: Box::new(moment.clone()),
152                body_type: Box::new(duration.clone()),
153            }),
154        };
155        ctx.add_declaration("moment_sub_moment", moment_moment_duration_type);
156
157        // Comparison operations: X -> X -> Bool
158        let date_date_bool_type = Term::Pi {
159            param: "_".to_string(),
160            param_type: Box::new(date.clone()),
161            body_type: Box::new(Term::Pi {
162                param: "_".to_string(),
163                param_type: Box::new(date),
164                body_type: Box::new(bool_type.clone()),
165            }),
166        };
167        ctx.add_declaration("date_lt", date_date_bool_type);
168
169        let moment_moment_bool_type = Term::Pi {
170            param: "_".to_string(),
171            param_type: Box::new(moment.clone()),
172            body_type: Box::new(Term::Pi {
173                param: "_".to_string(),
174                param_type: Box::new(moment),
175                body_type: Box::new(bool_type.clone()),
176            }),
177        };
178        ctx.add_declaration("moment_lt", moment_moment_bool_type);
179
180        let duration_duration_bool_type = Term::Pi {
181            param: "_".to_string(),
182            param_type: Box::new(duration.clone()),
183            body_type: Box::new(Term::Pi {
184                param: "_".to_string(),
185                param_type: Box::new(duration),
186                body_type: Box::new(bool_type),
187            }),
188        };
189        ctx.add_declaration("duration_lt", duration_duration_bool_type);
190    }
191
192    /// Entity : Type 0
193    ///
194    /// The domain of individuals for first-order logic.
195    /// Proper names like "Socrates" are declared as Entity.
196    /// Predicates like "Man" are declared as Entity → Prop.
197    fn register_entity(ctx: &mut Context) {
198        ctx.add_inductive("Entity", Term::Sort(Universe::Type(0)));
199    }
200
201    /// Nat : Type 0
202    /// Zero : Nat
203    /// Succ : Nat → Nat
204    fn register_nat(ctx: &mut Context) {
205        let nat = Term::Global("Nat".to_string());
206
207        // Nat : Type 0
208        ctx.add_inductive("Nat", Term::Sort(Universe::Type(0)));
209
210        // Zero : Nat
211        ctx.add_constructor("Zero", "Nat", nat.clone());
212
213        // Succ : Nat → Nat
214        ctx.add_constructor(
215            "Succ",
216            "Nat",
217            Term::Pi {
218                param: "_".to_string(),
219                param_type: Box::new(nat.clone()),
220                body_type: Box::new(nat),
221            },
222        );
223    }
224
225    /// Bool : Type 0
226    /// true : Bool
227    /// false : Bool
228    fn register_bool(ctx: &mut Context) {
229        let bool_type = Term::Global("Bool".to_string());
230
231        // Bool : Type 0
232        ctx.add_inductive("Bool", Term::Sort(Universe::Type(0)));
233
234        // true : Bool
235        ctx.add_constructor("true", "Bool", bool_type.clone());
236
237        // false : Bool
238        ctx.add_constructor("false", "Bool", bool_type);
239    }
240
241    /// TList : Type 0 -> Type 0
242    /// TNil : Π(A : Type 0). TList A
243    /// TCons : Π(A : Type 0). A -> TList A -> TList A
244    fn register_tlist(ctx: &mut Context) {
245        let type0 = Term::Sort(Universe::Type(0));
246        let a = Term::Var("A".to_string());
247
248        // TList : Type 0 -> Type 0
249        let tlist_type = Term::Pi {
250            param: "A".to_string(),
251            param_type: Box::new(type0.clone()),
252            body_type: Box::new(type0.clone()),
253        };
254        ctx.add_inductive("TList", tlist_type);
255
256        // TList A
257        let tlist_a = Term::App(
258            Box::new(Term::Global("TList".to_string())),
259            Box::new(a.clone()),
260        );
261
262        // TNil : Π(A : Type 0). TList A
263        let tnil_type = Term::Pi {
264            param: "A".to_string(),
265            param_type: Box::new(type0.clone()),
266            body_type: Box::new(tlist_a.clone()),
267        };
268        ctx.add_constructor("TNil", "TList", tnil_type);
269
270        // TCons : Π(A : Type 0). A -> TList A -> TList A
271        let tcons_type = Term::Pi {
272            param: "A".to_string(),
273            param_type: Box::new(type0),
274            body_type: Box::new(Term::Pi {
275                param: "_".to_string(),
276                param_type: Box::new(a.clone()),
277                body_type: Box::new(Term::Pi {
278                    param: "_".to_string(),
279                    param_type: Box::new(tlist_a.clone()),
280                    body_type: Box::new(tlist_a),
281                }),
282            }),
283        };
284        ctx.add_constructor("TCons", "TList", tcons_type);
285
286        // Convenience aliases for tactic lists (Syntax -> Derivation)
287        Self::register_tactic_list_helpers(ctx);
288    }
289
290    /// TTactics : Type 0 = TList (Syntax -> Derivation)
291    /// TacNil : TTactics
292    /// TacCons : (Syntax -> Derivation) -> TTactics -> TTactics
293    ///
294    /// Convenience wrappers to avoid explicit type arguments for tactic lists.
295    fn register_tactic_list_helpers(ctx: &mut Context) {
296        let syntax = Term::Global("Syntax".to_string());
297        let derivation = Term::Global("Derivation".to_string());
298
299        // Tactic type: Syntax -> Derivation
300        let tactic_type = Term::Pi {
301            param: "_".to_string(),
302            param_type: Box::new(syntax.clone()),
303            body_type: Box::new(derivation.clone()),
304        };
305
306        // TTactics = TList (Syntax -> Derivation)
307        let ttactics = Term::App(
308            Box::new(Term::Global("TList".to_string())),
309            Box::new(tactic_type.clone()),
310        );
311
312        // TTactics : Type 0
313        ctx.add_definition("TTactics".to_string(), Term::Sort(Universe::Type(0)), ttactics.clone());
314
315        // TacNil : TTactics = TNil (Syntax -> Derivation)
316        let tac_nil_body = Term::App(
317            Box::new(Term::Global("TNil".to_string())),
318            Box::new(tactic_type.clone()),
319        );
320        ctx.add_definition("TacNil".to_string(), ttactics.clone(), tac_nil_body);
321
322        // TacCons : (Syntax -> Derivation) -> TTactics -> TTactics
323        let tac_cons_type = Term::Pi {
324            param: "t".to_string(),
325            param_type: Box::new(tactic_type.clone()),
326            body_type: Box::new(Term::Pi {
327                param: "ts".to_string(),
328                param_type: Box::new(ttactics.clone()),
329                body_type: Box::new(ttactics.clone()),
330            }),
331        };
332
333        // TacCons t ts = TCons (Syntax -> Derivation) t ts
334        let tac_cons_body = Term::Lambda {
335            param: "t".to_string(),
336            param_type: Box::new(tactic_type.clone()),
337            body: Box::new(Term::Lambda {
338                param: "ts".to_string(),
339                param_type: Box::new(ttactics.clone()),
340                body: Box::new(Term::App(
341                    Box::new(Term::App(
342                        Box::new(Term::App(
343                            Box::new(Term::Global("TCons".to_string())),
344                            Box::new(tactic_type),
345                        )),
346                        Box::new(Term::Var("t".to_string())),
347                    )),
348                    Box::new(Term::Var("ts".to_string())),
349                )),
350            }),
351        };
352        ctx.add_definition("TacCons".to_string(), tac_cons_type, tac_cons_body);
353    }
354
355    /// True : Prop
356    /// I : True
357    fn register_true(ctx: &mut Context) {
358        ctx.add_inductive("True", Term::Sort(Universe::Prop));
359        ctx.add_constructor("I", "True", Term::Global("True".to_string()));
360    }
361
362    /// False : Prop
363    /// (no constructors)
364    fn register_false(ctx: &mut Context) {
365        ctx.add_inductive("False", Term::Sort(Universe::Prop));
366    }
367
368    /// Not : Prop -> Prop
369    /// Not P := P -> False
370    fn register_not(ctx: &mut Context) {
371        // Type: Π(P : Prop). Prop
372        let not_type = Term::Pi {
373            param: "P".to_string(),
374            param_type: Box::new(Term::Sort(Universe::Prop)),
375            body_type: Box::new(Term::Sort(Universe::Prop)),
376        };
377
378        // Body: λ(P : Prop). Π(_ : P). False
379        let not_body = Term::Lambda {
380            param: "P".to_string(),
381            param_type: Box::new(Term::Sort(Universe::Prop)),
382            body: Box::new(Term::Pi {
383                param: "_".to_string(),
384                param_type: Box::new(Term::Var("P".to_string())),
385                body_type: Box::new(Term::Global("False".to_string())),
386            }),
387        };
388
389        ctx.add_definition("Not".to_string(), not_type, not_body);
390    }
391
392    /// Eq : Π(A : Type 0). A → A → Prop
393    /// refl : Π(A : Type 0). Π(x : A). Eq A x x
394    fn register_eq(ctx: &mut Context) {
395        // Eq : Π(A : Type 0). A → A → Prop
396        let eq_type = Term::Pi {
397            param: "A".to_string(),
398            param_type: Box::new(Term::Sort(Universe::Type(0))),
399            body_type: Box::new(Term::Pi {
400                param: "x".to_string(),
401                param_type: Box::new(Term::Var("A".to_string())),
402                body_type: Box::new(Term::Pi {
403                    param: "y".to_string(),
404                    param_type: Box::new(Term::Var("A".to_string())),
405                    body_type: Box::new(Term::Sort(Universe::Prop)),
406                }),
407            }),
408        };
409        ctx.add_inductive("Eq", eq_type);
410
411        // refl : Π(A : Type 0). Π(x : A). Eq A x x
412        let refl_type = Term::Pi {
413            param: "A".to_string(),
414            param_type: Box::new(Term::Sort(Universe::Type(0))),
415            body_type: Box::new(Term::Pi {
416                param: "x".to_string(),
417                param_type: Box::new(Term::Var("A".to_string())),
418                body_type: Box::new(Term::App(
419                    Box::new(Term::App(
420                        Box::new(Term::App(
421                            Box::new(Term::Global("Eq".to_string())),
422                            Box::new(Term::Var("A".to_string())),
423                        )),
424                        Box::new(Term::Var("x".to_string())),
425                    )),
426                    Box::new(Term::Var("x".to_string())),
427                )),
428            }),
429        };
430        ctx.add_constructor("refl", "Eq", refl_type);
431
432        // Eq_rec : Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
433        // The eliminator for equality - Leibniz's Law
434        Self::register_eq_rec(ctx);
435
436        // Eq_sym : Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
437        Self::register_eq_sym(ctx);
438
439        // Eq_trans : Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
440        Self::register_eq_trans(ctx);
441    }
442
443    /// Eq_rec : Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
444    /// The eliminator for equality - Leibniz's Law / Substitution of Equals
445    fn register_eq_rec(ctx: &mut Context) {
446        let a = Term::Var("A".to_string());
447        let x = Term::Var("x".to_string());
448        let y = Term::Var("y".to_string());
449        let p = Term::Var("P".to_string());
450
451        // P x = P applied to x
452        let p_x = Term::App(Box::new(p.clone()), Box::new(x.clone()));
453
454        // P y = P applied to y
455        let p_y = Term::App(Box::new(p.clone()), Box::new(y.clone()));
456
457        // Eq A x y
458        let eq_a_x_y = Term::App(
459            Box::new(Term::App(
460                Box::new(Term::App(
461                    Box::new(Term::Global("Eq".to_string())),
462                    Box::new(a.clone()),
463                )),
464                Box::new(x.clone()),
465            )),
466            Box::new(y.clone()),
467        );
468
469        // P : A → Prop
470        let p_type = Term::Pi {
471            param: "_".to_string(),
472            param_type: Box::new(a.clone()),
473            body_type: Box::new(Term::Sort(Universe::Prop)),
474        };
475
476        // Full type: Π(A:Type). Π(x:A). Π(P:A→Prop). P x → Π(y:A). Eq A x y → P y
477        let eq_rec_type = Term::Pi {
478            param: "A".to_string(),
479            param_type: Box::new(Term::Sort(Universe::Type(0))),
480            body_type: Box::new(Term::Pi {
481                param: "x".to_string(),
482                param_type: Box::new(a.clone()),
483                body_type: Box::new(Term::Pi {
484                    param: "P".to_string(),
485                    param_type: Box::new(p_type),
486                    body_type: Box::new(Term::Pi {
487                        param: "_".to_string(),
488                        param_type: Box::new(p_x),
489                        body_type: Box::new(Term::Pi {
490                            param: "y".to_string(),
491                            param_type: Box::new(a),
492                            body_type: Box::new(Term::Pi {
493                                param: "_".to_string(),
494                                param_type: Box::new(eq_a_x_y),
495                                body_type: Box::new(p_y),
496                            }),
497                        }),
498                    }),
499                }),
500            }),
501        };
502
503        ctx.add_declaration("Eq_rec", eq_rec_type);
504    }
505
506    /// Eq_sym : Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
507    /// Symmetry of equality
508    fn register_eq_sym(ctx: &mut Context) {
509        let a = Term::Var("A".to_string());
510        let x = Term::Var("x".to_string());
511        let y = Term::Var("y".to_string());
512
513        // Eq A x y
514        let eq_a_x_y = Term::App(
515            Box::new(Term::App(
516                Box::new(Term::App(
517                    Box::new(Term::Global("Eq".to_string())),
518                    Box::new(a.clone()),
519                )),
520                Box::new(x.clone()),
521            )),
522            Box::new(y.clone()),
523        );
524
525        // Eq A y x
526        let eq_a_y_x = Term::App(
527            Box::new(Term::App(
528                Box::new(Term::App(
529                    Box::new(Term::Global("Eq".to_string())),
530                    Box::new(a.clone()),
531                )),
532                Box::new(y.clone()),
533            )),
534            Box::new(x.clone()),
535        );
536
537        // Π(A:Type). Π(x:A). Π(y:A). Eq A x y → Eq A y x
538        let eq_sym_type = Term::Pi {
539            param: "A".to_string(),
540            param_type: Box::new(Term::Sort(Universe::Type(0))),
541            body_type: Box::new(Term::Pi {
542                param: "x".to_string(),
543                param_type: Box::new(a.clone()),
544                body_type: Box::new(Term::Pi {
545                    param: "y".to_string(),
546                    param_type: Box::new(a),
547                    body_type: Box::new(Term::Pi {
548                        param: "_".to_string(),
549                        param_type: Box::new(eq_a_x_y),
550                        body_type: Box::new(eq_a_y_x),
551                    }),
552                }),
553            }),
554        };
555
556        ctx.add_declaration("Eq_sym", eq_sym_type);
557    }
558
559    /// Eq_trans : Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
560    /// Transitivity of equality
561    fn register_eq_trans(ctx: &mut Context) {
562        let a = Term::Var("A".to_string());
563        let x = Term::Var("x".to_string());
564        let y = Term::Var("y".to_string());
565        let z = Term::Var("z".to_string());
566
567        // Eq A x y
568        let eq_a_x_y = Term::App(
569            Box::new(Term::App(
570                Box::new(Term::App(
571                    Box::new(Term::Global("Eq".to_string())),
572                    Box::new(a.clone()),
573                )),
574                Box::new(x.clone()),
575            )),
576            Box::new(y.clone()),
577        );
578
579        // Eq A y z
580        let eq_a_y_z = Term::App(
581            Box::new(Term::App(
582                Box::new(Term::App(
583                    Box::new(Term::Global("Eq".to_string())),
584                    Box::new(a.clone()),
585                )),
586                Box::new(y.clone()),
587            )),
588            Box::new(z.clone()),
589        );
590
591        // Eq A x z
592        let eq_a_x_z = Term::App(
593            Box::new(Term::App(
594                Box::new(Term::App(
595                    Box::new(Term::Global("Eq".to_string())),
596                    Box::new(a.clone()),
597                )),
598                Box::new(x.clone()),
599            )),
600            Box::new(z.clone()),
601        );
602
603        // Π(A:Type). Π(x:A). Π(y:A). Π(z:A). Eq A x y → Eq A y z → Eq A x z
604        let eq_trans_type = Term::Pi {
605            param: "A".to_string(),
606            param_type: Box::new(Term::Sort(Universe::Type(0))),
607            body_type: Box::new(Term::Pi {
608                param: "x".to_string(),
609                param_type: Box::new(a.clone()),
610                body_type: Box::new(Term::Pi {
611                    param: "y".to_string(),
612                    param_type: Box::new(a.clone()),
613                    body_type: Box::new(Term::Pi {
614                        param: "z".to_string(),
615                        param_type: Box::new(a),
616                        body_type: Box::new(Term::Pi {
617                            param: "_".to_string(),
618                            param_type: Box::new(eq_a_x_y),
619                            body_type: Box::new(Term::Pi {
620                                param: "_".to_string(),
621                                param_type: Box::new(eq_a_y_z),
622                                body_type: Box::new(eq_a_x_z),
623                            }),
624                        }),
625                    }),
626                }),
627            }),
628        };
629
630        ctx.add_declaration("Eq_trans", eq_trans_type);
631    }
632
633    /// And : Prop → Prop → Prop
634    /// conj : Π(P : Prop). Π(Q : Prop). P → Q → And P Q
635    fn register_and(ctx: &mut Context) {
636        // And : Prop → Prop → Prop
637        let and_type = Term::Pi {
638            param: "P".to_string(),
639            param_type: Box::new(Term::Sort(Universe::Prop)),
640            body_type: Box::new(Term::Pi {
641                param: "Q".to_string(),
642                param_type: Box::new(Term::Sort(Universe::Prop)),
643                body_type: Box::new(Term::Sort(Universe::Prop)),
644            }),
645        };
646        ctx.add_inductive("And", and_type);
647
648        // conj : Π(P : Prop). Π(Q : Prop). P → Q → And P Q
649        let conj_type = Term::Pi {
650            param: "P".to_string(),
651            param_type: Box::new(Term::Sort(Universe::Prop)),
652            body_type: Box::new(Term::Pi {
653                param: "Q".to_string(),
654                param_type: Box::new(Term::Sort(Universe::Prop)),
655                body_type: Box::new(Term::Pi {
656                    param: "p".to_string(),
657                    param_type: Box::new(Term::Var("P".to_string())),
658                    body_type: Box::new(Term::Pi {
659                        param: "q".to_string(),
660                        param_type: Box::new(Term::Var("Q".to_string())),
661                        body_type: Box::new(Term::App(
662                            Box::new(Term::App(
663                                Box::new(Term::Global("And".to_string())),
664                                Box::new(Term::Var("P".to_string())),
665                            )),
666                            Box::new(Term::Var("Q".to_string())),
667                        )),
668                    }),
669                }),
670            }),
671        };
672        ctx.add_constructor("conj", "And", conj_type);
673    }
674
675    /// Or : Prop → Prop → Prop
676    /// left : Π(P : Prop). Π(Q : Prop). P → Or P Q
677    /// right : Π(P : Prop). Π(Q : Prop). Q → Or P Q
678    fn register_or(ctx: &mut Context) {
679        // Or : Prop → Prop → Prop
680        let or_type = Term::Pi {
681            param: "P".to_string(),
682            param_type: Box::new(Term::Sort(Universe::Prop)),
683            body_type: Box::new(Term::Pi {
684                param: "Q".to_string(),
685                param_type: Box::new(Term::Sort(Universe::Prop)),
686                body_type: Box::new(Term::Sort(Universe::Prop)),
687            }),
688        };
689        ctx.add_inductive("Or", or_type);
690
691        // left : Π(P : Prop). Π(Q : Prop). P → Or P Q
692        let left_type = Term::Pi {
693            param: "P".to_string(),
694            param_type: Box::new(Term::Sort(Universe::Prop)),
695            body_type: Box::new(Term::Pi {
696                param: "Q".to_string(),
697                param_type: Box::new(Term::Sort(Universe::Prop)),
698                body_type: Box::new(Term::Pi {
699                    param: "p".to_string(),
700                    param_type: Box::new(Term::Var("P".to_string())),
701                    body_type: Box::new(Term::App(
702                        Box::new(Term::App(
703                            Box::new(Term::Global("Or".to_string())),
704                            Box::new(Term::Var("P".to_string())),
705                        )),
706                        Box::new(Term::Var("Q".to_string())),
707                    )),
708                }),
709            }),
710        };
711        ctx.add_constructor("left", "Or", left_type);
712
713        // right : Π(P : Prop). Π(Q : Prop). Q → Or P Q
714        let right_type = Term::Pi {
715            param: "P".to_string(),
716            param_type: Box::new(Term::Sort(Universe::Prop)),
717            body_type: Box::new(Term::Pi {
718                param: "Q".to_string(),
719                param_type: Box::new(Term::Sort(Universe::Prop)),
720                body_type: Box::new(Term::Pi {
721                    param: "q".to_string(),
722                    param_type: Box::new(Term::Var("Q".to_string())),
723                    body_type: Box::new(Term::App(
724                        Box::new(Term::App(
725                            Box::new(Term::Global("Or".to_string())),
726                            Box::new(Term::Var("P".to_string())),
727                        )),
728                        Box::new(Term::Var("Q".to_string())),
729                    )),
730                }),
731            }),
732        };
733        ctx.add_constructor("right", "Or", right_type);
734    }
735
736    /// Ex : Π(A : Type 0). (A → Prop) → Prop
737    /// witness : Π(A : Type 0). Π(P : A → Prop). Π(x : A). P x → Ex A P
738    ///
739    /// Ex is the existential type for propositions.
740    /// Ex A P means "there exists an x:A such that P(x)"
741    fn register_ex(ctx: &mut Context) {
742        // Ex : Π(A : Type 0). (A → Prop) → Prop
743        let ex_type = Term::Pi {
744            param: "A".to_string(),
745            param_type: Box::new(Term::Sort(Universe::Type(0))),
746            body_type: Box::new(Term::Pi {
747                param: "P".to_string(),
748                param_type: Box::new(Term::Pi {
749                    param: "_".to_string(),
750                    param_type: Box::new(Term::Var("A".to_string())),
751                    body_type: Box::new(Term::Sort(Universe::Prop)),
752                }),
753                body_type: Box::new(Term::Sort(Universe::Prop)),
754            }),
755        };
756        ctx.add_inductive("Ex", ex_type);
757
758        // witness : Π(A : Type 0). Π(P : A → Prop). Π(x : A). P x → Ex A P
759        //
760        // To construct an existential proof, provide:
761        // - A: the type being quantified over
762        // - P: the predicate
763        // - x: the witness (an element of A)
764        // - proof: evidence that P(x) holds
765        let a = Term::Var("A".to_string());
766        let p = Term::Var("P".to_string());
767        let x = Term::Var("x".to_string());
768
769        // P x = P applied to x
770        let p_x = Term::App(Box::new(p.clone()), Box::new(x.clone()));
771
772        // Ex A P = Ex applied to A, then to P
773        let ex_a_p = Term::App(
774            Box::new(Term::App(
775                Box::new(Term::Global("Ex".to_string())),
776                Box::new(a.clone()),
777            )),
778            Box::new(p.clone()),
779        );
780
781        let witness_type = Term::Pi {
782            param: "A".to_string(),
783            param_type: Box::new(Term::Sort(Universe::Type(0))),
784            body_type: Box::new(Term::Pi {
785                param: "P".to_string(),
786                param_type: Box::new(Term::Pi {
787                    param: "_".to_string(),
788                    param_type: Box::new(a.clone()),
789                    body_type: Box::new(Term::Sort(Universe::Prop)),
790                }),
791                body_type: Box::new(Term::Pi {
792                    param: "x".to_string(),
793                    param_type: Box::new(a),
794                    body_type: Box::new(Term::Pi {
795                        param: "_".to_string(),
796                        param_type: Box::new(p_x),
797                        body_type: Box::new(ex_a_p),
798                    }),
799                }),
800            }),
801        };
802        ctx.add_constructor("witness", "Ex", witness_type);
803    }
804
805    // -------------------------------------------------------------------------
806    // Reflection System (Deep Embedding)
807    // -------------------------------------------------------------------------
808
809    /// Reflection types for deep embedding.
810    ///
811    /// Univ : Type 0 (representation of universes)
812    /// Syntax : Type 0 (representation of terms with De Bruijn indices)
813    /// syn_size : Syntax -> Int (compute size of syntax tree)
814    /// syn_max_var : Syntax -> Int (compute max free variable index)
815    fn register_reflection(ctx: &mut Context) {
816        Self::register_univ(ctx);
817        Self::register_syntax(ctx);
818        Self::register_syn_size(ctx);
819        Self::register_syn_max_var(ctx);
820        Self::register_syn_lift(ctx);
821        Self::register_syn_subst(ctx);
822        Self::register_syn_beta(ctx);
823        Self::register_syn_step(ctx);
824        Self::register_syn_eval(ctx);
825        Self::register_syn_quote(ctx);
826        Self::register_syn_diag(ctx);
827        Self::register_derivation(ctx);
828        Self::register_concludes(ctx);
829        Self::register_try_refl(ctx);
830        Self::register_try_compute(ctx);
831        Self::register_try_cong(ctx);
832        Self::register_tact_fail(ctx);
833        Self::register_tact_orelse(ctx);
834        Self::register_tact_try(ctx);
835        Self::register_tact_repeat(ctx);
836        Self::register_tact_then(ctx);
837        Self::register_tact_first(ctx);
838        Self::register_tact_solve(ctx);
839        Self::register_try_ring(ctx);
840        Self::register_try_lia(ctx);
841        Self::register_try_cc(ctx);
842        Self::register_try_simp(ctx);
843        Self::register_try_omega(ctx);
844        Self::register_try_auto(ctx);
845        Self::register_try_induction(ctx);
846        Self::register_induction_helpers(ctx);
847        Self::register_try_inversion_tactic(ctx);
848        Self::register_operator_tactics(ctx);
849    }
850
851    /// Univ : Type 0 (representation of universes)
852    /// UProp : Univ
853    /// UType : Int -> Univ
854    fn register_univ(ctx: &mut Context) {
855        let univ = Term::Global("Univ".to_string());
856        let int = Term::Global("Int".to_string());
857
858        // Univ : Type 0
859        ctx.add_inductive("Univ", Term::Sort(Universe::Type(0)));
860
861        // UProp : Univ
862        ctx.add_constructor("UProp", "Univ", univ.clone());
863
864        // UType : Int -> Univ
865        ctx.add_constructor(
866            "UType",
867            "Univ",
868            Term::Pi {
869                param: "_".to_string(),
870                param_type: Box::new(int),
871                body_type: Box::new(univ),
872            },
873        );
874    }
875
876    /// Syntax : Type 0 (representation of terms with De Bruijn indices)
877    ///
878    /// SVar : Int -> Syntax (De Bruijn variable index)
879    /// SGlobal : Int -> Syntax (global reference by ID)
880    /// SSort : Univ -> Syntax (universe)
881    /// SApp : Syntax -> Syntax -> Syntax (application)
882    /// SLam : Syntax -> Syntax -> Syntax (lambda: param_type, body)
883    /// SPi : Syntax -> Syntax -> Syntax (pi: param_type, body_type)
884    fn register_syntax(ctx: &mut Context) {
885        let syntax = Term::Global("Syntax".to_string());
886        let int = Term::Global("Int".to_string());
887        let univ = Term::Global("Univ".to_string());
888
889        // Syntax : Type 0
890        ctx.add_inductive("Syntax", Term::Sort(Universe::Type(0)));
891
892        // SVar : Int -> Syntax (De Bruijn index)
893        ctx.add_constructor(
894            "SVar",
895            "Syntax",
896            Term::Pi {
897                param: "_".to_string(),
898                param_type: Box::new(int.clone()),
899                body_type: Box::new(syntax.clone()),
900            },
901        );
902
903        // SGlobal : Int -> Syntax (global reference by ID)
904        ctx.add_constructor(
905            "SGlobal",
906            "Syntax",
907            Term::Pi {
908                param: "_".to_string(),
909                param_type: Box::new(int.clone()),
910                body_type: Box::new(syntax.clone()),
911            },
912        );
913
914        // SSort : Univ -> Syntax
915        ctx.add_constructor(
916            "SSort",
917            "Syntax",
918            Term::Pi {
919                param: "_".to_string(),
920                param_type: Box::new(univ),
921                body_type: Box::new(syntax.clone()),
922            },
923        );
924
925        // SApp : Syntax -> Syntax -> Syntax
926        ctx.add_constructor(
927            "SApp",
928            "Syntax",
929            Term::Pi {
930                param: "_".to_string(),
931                param_type: Box::new(syntax.clone()),
932                body_type: Box::new(Term::Pi {
933                    param: "_".to_string(),
934                    param_type: Box::new(syntax.clone()),
935                    body_type: Box::new(syntax.clone()),
936                }),
937            },
938        );
939
940        // SLam : Syntax -> Syntax -> Syntax (param_type, body)
941        ctx.add_constructor(
942            "SLam",
943            "Syntax",
944            Term::Pi {
945                param: "_".to_string(),
946                param_type: Box::new(syntax.clone()),
947                body_type: Box::new(Term::Pi {
948                    param: "_".to_string(),
949                    param_type: Box::new(syntax.clone()),
950                    body_type: Box::new(syntax.clone()),
951                }),
952            },
953        );
954
955        // SPi : Syntax -> Syntax -> Syntax (param_type, body_type)
956        ctx.add_constructor(
957            "SPi",
958            "Syntax",
959            Term::Pi {
960                param: "_".to_string(),
961                param_type: Box::new(syntax.clone()),
962                body_type: Box::new(Term::Pi {
963                    param: "_".to_string(),
964                    param_type: Box::new(syntax.clone()),
965                    body_type: Box::new(syntax.clone()),
966                }),
967            },
968        );
969
970        // SLit : Int -> Syntax (integer literal in quoted syntax)
971        ctx.add_constructor(
972            "SLit",
973            "Syntax",
974            Term::Pi {
975                param: "_".to_string(),
976                param_type: Box::new(int),
977                body_type: Box::new(syntax.clone()),
978            },
979        );
980
981        // SName : Text -> Syntax (named global reference)
982        let text = Term::Global("Text".to_string());
983        ctx.add_constructor(
984            "SName",
985            "Syntax",
986            Term::Pi {
987                param: "_".to_string(),
988                param_type: Box::new(text),
989                body_type: Box::new(syntax),
990            },
991        );
992    }
993
994    /// syn_size : Syntax -> Int
995    ///
996    /// Computes the number of nodes in a syntax tree.
997    /// Computational behavior defined in reduction.rs.
998    fn register_syn_size(ctx: &mut Context) {
999        let syntax = Term::Global("Syntax".to_string());
1000        let int = Term::Global("Int".to_string());
1001
1002        // syn_size : Syntax -> Int
1003        let syn_size_type = Term::Pi {
1004            param: "_".to_string(),
1005            param_type: Box::new(syntax),
1006            body_type: Box::new(int),
1007        };
1008
1009        ctx.add_declaration("syn_size", syn_size_type);
1010    }
1011
1012    /// syn_max_var : Syntax -> Int
1013    ///
1014    /// Returns the maximum free variable index in a syntax term.
1015    /// Returns -1 if the term is closed (all variables bound).
1016    /// Computational behavior defined in reduction.rs.
1017    fn register_syn_max_var(ctx: &mut Context) {
1018        let syntax = Term::Global("Syntax".to_string());
1019        let int = Term::Global("Int".to_string());
1020
1021        let syn_max_var_type = Term::Pi {
1022            param: "_".to_string(),
1023            param_type: Box::new(syntax),
1024            body_type: Box::new(int),
1025        };
1026
1027        ctx.add_declaration("syn_max_var", syn_max_var_type);
1028    }
1029
1030    // -------------------------------------------------------------------------
1031    // De Bruijn Operations (Substitution)
1032    // -------------------------------------------------------------------------
1033
1034    /// syn_lift : Int -> Int -> Syntax -> Syntax
1035    ///
1036    /// Shifts free variables (index >= cutoff) by amount.
1037    /// - syn_lift amount cutoff term
1038    /// - Variables with index < cutoff are bound -> unchanged
1039    /// - Variables with index >= cutoff are free -> add amount
1040    /// Computational behavior defined in reduction.rs.
1041    fn register_syn_lift(ctx: &mut Context) {
1042        let syntax = Term::Global("Syntax".to_string());
1043        let int = Term::Global("Int".to_string());
1044
1045        // syn_lift : Int -> Int -> Syntax -> Syntax
1046        let syn_lift_type = Term::Pi {
1047            param: "_".to_string(),
1048            param_type: Box::new(int.clone()),
1049            body_type: Box::new(Term::Pi {
1050                param: "_".to_string(),
1051                param_type: Box::new(int),
1052                body_type: Box::new(Term::Pi {
1053                    param: "_".to_string(),
1054                    param_type: Box::new(syntax.clone()),
1055                    body_type: Box::new(syntax),
1056                }),
1057            }),
1058        };
1059
1060        ctx.add_declaration("syn_lift", syn_lift_type);
1061    }
1062
1063    /// syn_subst : Syntax -> Int -> Syntax -> Syntax
1064    ///
1065    /// Substitutes replacement for variable at index in term.
1066    /// - syn_subst replacement index term
1067    /// - If term is SVar k and k == index, return replacement
1068    /// - If term is SVar k and k != index, return term unchanged
1069    /// - For binders, increment index and lift replacement
1070    /// Computational behavior defined in reduction.rs.
1071    fn register_syn_subst(ctx: &mut Context) {
1072        let syntax = Term::Global("Syntax".to_string());
1073        let int = Term::Global("Int".to_string());
1074
1075        // syn_subst : Syntax -> Int -> Syntax -> Syntax
1076        let syn_subst_type = Term::Pi {
1077            param: "_".to_string(),
1078            param_type: Box::new(syntax.clone()),
1079            body_type: Box::new(Term::Pi {
1080                param: "_".to_string(),
1081                param_type: Box::new(int),
1082                body_type: Box::new(Term::Pi {
1083                    param: "_".to_string(),
1084                    param_type: Box::new(syntax.clone()),
1085                    body_type: Box::new(syntax),
1086                }),
1087            }),
1088        };
1089
1090        ctx.add_declaration("syn_subst", syn_subst_type);
1091    }
1092
1093    // -------------------------------------------------------------------------
1094    // Beta Reduction (Computation)
1095    // -------------------------------------------------------------------------
1096
1097    /// syn_beta : Syntax -> Syntax -> Syntax
1098    ///
1099    /// Beta reduction: substitute arg for variable 0 in body.
1100    /// - syn_beta body arg = syn_subst arg 0 body
1101    /// Computational behavior defined in reduction.rs.
1102    fn register_syn_beta(ctx: &mut Context) {
1103        let syntax = Term::Global("Syntax".to_string());
1104
1105        // syn_beta : Syntax -> Syntax -> Syntax
1106        let syn_beta_type = Term::Pi {
1107            param: "_".to_string(),
1108            param_type: Box::new(syntax.clone()),
1109            body_type: Box::new(Term::Pi {
1110                param: "_".to_string(),
1111                param_type: Box::new(syntax.clone()),
1112                body_type: Box::new(syntax),
1113            }),
1114        };
1115
1116        ctx.add_declaration("syn_beta", syn_beta_type);
1117    }
1118
1119    /// syn_step : Syntax -> Syntax
1120    ///
1121    /// Single-step head reduction. Finds first beta redex and reduces.
1122    /// - If SApp (SLam T body) arg: perform beta reduction
1123    /// - If SApp f x where f is reducible: reduce f
1124    /// - Otherwise: return unchanged (stuck or value)
1125    /// Computational behavior defined in reduction.rs.
1126    fn register_syn_step(ctx: &mut Context) {
1127        let syntax = Term::Global("Syntax".to_string());
1128
1129        // syn_step : Syntax -> Syntax
1130        let syn_step_type = Term::Pi {
1131            param: "_".to_string(),
1132            param_type: Box::new(syntax.clone()),
1133            body_type: Box::new(syntax),
1134        };
1135
1136        ctx.add_declaration("syn_step", syn_step_type);
1137    }
1138
1139    // -------------------------------------------------------------------------
1140    // Bounded Evaluation
1141    // -------------------------------------------------------------------------
1142
1143    /// syn_eval : Int -> Syntax -> Syntax
1144    ///
1145    /// Bounded evaluation: reduce for up to N steps.
1146    /// - syn_eval fuel term
1147    /// - If fuel <= 0: return term unchanged
1148    /// - Otherwise: step and repeat until normal form or fuel exhausted
1149    /// Computational behavior defined in reduction.rs.
1150    fn register_syn_eval(ctx: &mut Context) {
1151        let syntax = Term::Global("Syntax".to_string());
1152        let int = Term::Global("Int".to_string());
1153
1154        // syn_eval : Int -> Syntax -> Syntax
1155        let syn_eval_type = Term::Pi {
1156            param: "_".to_string(),
1157            param_type: Box::new(int),
1158            body_type: Box::new(Term::Pi {
1159                param: "_".to_string(),
1160                param_type: Box::new(syntax.clone()),
1161                body_type: Box::new(syntax),
1162            }),
1163        };
1164
1165        ctx.add_declaration("syn_eval", syn_eval_type);
1166    }
1167
1168    // -------------------------------------------------------------------------
1169    // Reification (Quote)
1170    // -------------------------------------------------------------------------
1171
1172    /// syn_quote : Syntax -> Syntax
1173    ///
1174    /// Converts a Syntax value to Syntax code that constructs it.
1175    /// Computational behavior defined in reduction.rs.
1176    fn register_syn_quote(ctx: &mut Context) {
1177        let syntax = Term::Global("Syntax".to_string());
1178
1179        // syn_quote : Syntax -> Syntax
1180        let syn_quote_type = Term::Pi {
1181            param: "_".to_string(),
1182            param_type: Box::new(syntax.clone()),
1183            body_type: Box::new(syntax),
1184        };
1185
1186        ctx.add_declaration("syn_quote", syn_quote_type);
1187    }
1188
1189    // -------------------------------------------------------------------------
1190    // Diagonalization (Self-Reference)
1191    // -------------------------------------------------------------------------
1192
1193    /// syn_diag : Syntax -> Syntax
1194    ///
1195    /// The diagonal function: syn_diag x = syn_subst (syn_quote x) 0 x
1196    /// This is the key construction for self-reference and the diagonal lemma.
1197    fn register_syn_diag(ctx: &mut Context) {
1198        let syntax = Term::Global("Syntax".to_string());
1199
1200        let syn_diag_type = Term::Pi {
1201            param: "_".to_string(),
1202            param_type: Box::new(syntax.clone()),
1203            body_type: Box::new(syntax),
1204        };
1205
1206        ctx.add_declaration("syn_diag", syn_diag_type);
1207    }
1208
1209    // -------------------------------------------------------------------------
1210    // Inference Rules (Proof Trees)
1211    // -------------------------------------------------------------------------
1212
1213    /// Derivation : Type 0 (deep embedding of proof trees)
1214    ///
1215    /// DAxiom : Syntax -> Derivation (introduce an axiom)
1216    /// DModusPonens : Derivation -> Derivation -> Derivation (A->B, A |- B)
1217    /// DUnivIntro : Derivation -> Derivation (P(x) |- forall x. P(x))
1218    /// DUnivElim : Derivation -> Syntax -> Derivation (forall x. P(x), t |- P(t))
1219    fn register_derivation(ctx: &mut Context) {
1220        let syntax = Term::Global("Syntax".to_string());
1221        let derivation = Term::Global("Derivation".to_string());
1222
1223        // Derivation : Type 0
1224        ctx.add_inductive("Derivation", Term::Sort(Universe::Type(0)));
1225
1226        // DAxiom : Syntax -> Derivation
1227        ctx.add_constructor(
1228            "DAxiom",
1229            "Derivation",
1230            Term::Pi {
1231                param: "_".to_string(),
1232                param_type: Box::new(syntax.clone()),
1233                body_type: Box::new(derivation.clone()),
1234            },
1235        );
1236
1237        // DModusPonens : Derivation -> Derivation -> Derivation
1238        ctx.add_constructor(
1239            "DModusPonens",
1240            "Derivation",
1241            Term::Pi {
1242                param: "_".to_string(),
1243                param_type: Box::new(derivation.clone()),
1244                body_type: Box::new(Term::Pi {
1245                    param: "_".to_string(),
1246                    param_type: Box::new(derivation.clone()),
1247                    body_type: Box::new(derivation.clone()),
1248                }),
1249            },
1250        );
1251
1252        // DUnivIntro : Derivation -> Derivation
1253        ctx.add_constructor(
1254            "DUnivIntro",
1255            "Derivation",
1256            Term::Pi {
1257                param: "_".to_string(),
1258                param_type: Box::new(derivation.clone()),
1259                body_type: Box::new(derivation.clone()),
1260            },
1261        );
1262
1263        // DUnivElim : Derivation -> Syntax -> Derivation
1264        ctx.add_constructor(
1265            "DUnivElim",
1266            "Derivation",
1267            Term::Pi {
1268                param: "_".to_string(),
1269                param_type: Box::new(derivation.clone()),
1270                body_type: Box::new(Term::Pi {
1271                    param: "_".to_string(),
1272                    param_type: Box::new(syntax.clone()),
1273                    body_type: Box::new(derivation.clone()),
1274                }),
1275            },
1276        );
1277
1278        // DRefl : Syntax -> Syntax -> Derivation
1279        // DRefl T a proves (Eq T a a)
1280        ctx.add_constructor(
1281            "DRefl",
1282            "Derivation",
1283            Term::Pi {
1284                param: "_".to_string(),
1285                param_type: Box::new(syntax.clone()),
1286                body_type: Box::new(Term::Pi {
1287                    param: "_".to_string(),
1288                    param_type: Box::new(syntax.clone()),
1289                    body_type: Box::new(derivation.clone()),
1290                }),
1291            },
1292        );
1293
1294        // DInduction : Syntax -> Derivation -> Derivation -> Derivation
1295        // DInduction motive base step proves (∀n:Nat. motive n) via induction
1296        // - motive: λn:Nat. P(n) as Syntax
1297        // - base: proof of P(Zero)
1298        // - step: proof of ∀k:Nat. P(k) → P(Succ k)
1299        ctx.add_constructor(
1300            "DInduction",
1301            "Derivation",
1302            Term::Pi {
1303                param: "_".to_string(),
1304                param_type: Box::new(syntax.clone()), // motive
1305                body_type: Box::new(Term::Pi {
1306                    param: "_".to_string(),
1307                    param_type: Box::new(derivation.clone()), // base proof
1308                    body_type: Box::new(Term::Pi {
1309                        param: "_".to_string(),
1310                        param_type: Box::new(derivation.clone()), // step proof
1311                        body_type: Box::new(derivation.clone()),
1312                    }),
1313                }),
1314            },
1315        );
1316
1317        // DCompute : Syntax -> Derivation
1318        // DCompute goal proves goal by computation
1319        // - Validates that goal is (Eq T A B) and eval(A) == eval(B)
1320        ctx.add_constructor(
1321            "DCompute",
1322            "Derivation",
1323            Term::Pi {
1324                param: "_".to_string(),
1325                param_type: Box::new(syntax.clone()),
1326                body_type: Box::new(derivation.clone()),
1327            },
1328        );
1329
1330        // DCong : Syntax -> Derivation -> Derivation
1331        // DCong context eq_proof proves congruence
1332        // - context: SLam T body (function with hole at SVar 0)
1333        // - eq_proof: proof of (Eq T a b)
1334        // - Result: proof of (Eq T (body[0:=a]) (body[0:=b]))
1335        ctx.add_constructor(
1336            "DCong",
1337            "Derivation",
1338            Term::Pi {
1339                param: "_".to_string(),
1340                param_type: Box::new(syntax.clone()), // context
1341                body_type: Box::new(Term::Pi {
1342                    param: "_".to_string(),
1343                    param_type: Box::new(derivation.clone()), // eq_proof
1344                    body_type: Box::new(derivation.clone()),
1345                }),
1346            },
1347        );
1348
1349        // DCase : Derivation -> Derivation -> Derivation
1350        // Cons cell for case proofs in DElim
1351        ctx.add_constructor(
1352            "DCase",
1353            "Derivation",
1354            Term::Pi {
1355                param: "_".to_string(),
1356                param_type: Box::new(derivation.clone()), // head (case proof)
1357                body_type: Box::new(Term::Pi {
1358                    param: "_".to_string(),
1359                    param_type: Box::new(derivation.clone()), // tail (rest of cases)
1360                    body_type: Box::new(derivation.clone()),
1361                }),
1362            },
1363        );
1364
1365        // DCaseEnd : Derivation
1366        // Nil for case proofs in DElim
1367        ctx.add_constructor("DCaseEnd", "Derivation", derivation.clone());
1368
1369        // DElim : Syntax -> Syntax -> Derivation -> Derivation
1370        // Generic elimination for any inductive type
1371        // - ind_type: the inductive type (e.g., SName "Nat" or SApp (SName "List") A)
1372        // - motive: SLam param_type body (the property to prove)
1373        // - cases: DCase chain with one proof per constructor
1374        ctx.add_constructor(
1375            "DElim",
1376            "Derivation",
1377            Term::Pi {
1378                param: "_".to_string(),
1379                param_type: Box::new(syntax.clone()), // ind_type
1380                body_type: Box::new(Term::Pi {
1381                    param: "_".to_string(),
1382                    param_type: Box::new(syntax.clone()), // motive
1383                    body_type: Box::new(Term::Pi {
1384                        param: "_".to_string(),
1385                        param_type: Box::new(derivation.clone()), // cases
1386                        body_type: Box::new(derivation.clone()),
1387                    }),
1388                }),
1389            },
1390        );
1391
1392        // DInversion : Syntax -> Derivation
1393        // Proves False when no constructor can build the given hypothesis.
1394        // - hyp_type: the Syntax representation of the hypothesis (e.g., SApp (SName "Even") three)
1395        // - Returns proof of False if verified that all constructors are impossible
1396        ctx.add_constructor(
1397            "DInversion",
1398            "Derivation",
1399            Term::Pi {
1400                param: "_".to_string(),
1401                param_type: Box::new(syntax.clone()),
1402                body_type: Box::new(derivation.clone()),
1403            },
1404        );
1405
1406        // DRewrite : Derivation -> Syntax -> Syntax -> Derivation
1407        // Stores: eq_proof, original_goal, new_goal
1408        // Given eq_proof : Eq A x y, rewrites goal by replacing x with y
1409        ctx.add_constructor(
1410            "DRewrite",
1411            "Derivation",
1412            Term::Pi {
1413                param: "_".to_string(),
1414                param_type: Box::new(derivation.clone()), // eq_proof
1415                body_type: Box::new(Term::Pi {
1416                    param: "_".to_string(),
1417                    param_type: Box::new(syntax.clone()), // original_goal
1418                    body_type: Box::new(Term::Pi {
1419                        param: "_".to_string(),
1420                        param_type: Box::new(syntax.clone()), // new_goal
1421                        body_type: Box::new(derivation.clone()),
1422                    }),
1423                }),
1424            },
1425        );
1426
1427        // DDestruct : Syntax -> Syntax -> Derivation -> Derivation
1428        // Case analysis without induction hypotheses
1429        // - ind_type: the inductive type
1430        // - motive: the property to prove
1431        // - cases: DCase chain with proofs for each constructor
1432        ctx.add_constructor(
1433            "DDestruct",
1434            "Derivation",
1435            Term::Pi {
1436                param: "_".to_string(),
1437                param_type: Box::new(syntax.clone()), // ind_type
1438                body_type: Box::new(Term::Pi {
1439                    param: "_".to_string(),
1440                    param_type: Box::new(syntax.clone()), // motive
1441                    body_type: Box::new(Term::Pi {
1442                        param: "_".to_string(),
1443                        param_type: Box::new(derivation.clone()), // cases
1444                        body_type: Box::new(derivation.clone()),
1445                    }),
1446                }),
1447            },
1448        );
1449
1450        // DApply : Syntax -> Derivation -> Syntax -> Syntax -> Derivation
1451        // Manual backward chaining
1452        // - hyp_name: name of hypothesis
1453        // - hyp_proof: proof of the hypothesis
1454        // - original_goal: the goal we started with
1455        // - new_goal: the antecedent we need to prove
1456        ctx.add_constructor(
1457            "DApply",
1458            "Derivation",
1459            Term::Pi {
1460                param: "_".to_string(),
1461                param_type: Box::new(syntax.clone()), // hyp_name
1462                body_type: Box::new(Term::Pi {
1463                    param: "_".to_string(),
1464                    param_type: Box::new(derivation.clone()), // hyp_proof
1465                    body_type: Box::new(Term::Pi {
1466                        param: "_".to_string(),
1467                        param_type: Box::new(syntax.clone()), // original_goal
1468                        body_type: Box::new(Term::Pi {
1469                            param: "_".to_string(),
1470                            param_type: Box::new(syntax), // new_goal
1471                            body_type: Box::new(derivation),
1472                        }),
1473                    }),
1474                }),
1475            },
1476        );
1477    }
1478
1479    /// concludes : Derivation -> Syntax
1480    ///
1481    /// Extracts the conclusion from a derivation.
1482    /// Computational behavior defined in reduction.rs.
1483    fn register_concludes(ctx: &mut Context) {
1484        let derivation = Term::Global("Derivation".to_string());
1485        let syntax = Term::Global("Syntax".to_string());
1486
1487        // concludes : Derivation -> Syntax
1488        let concludes_type = Term::Pi {
1489            param: "_".to_string(),
1490            param_type: Box::new(derivation),
1491            body_type: Box::new(syntax),
1492        };
1493
1494        ctx.add_declaration("concludes", concludes_type);
1495    }
1496
1497    // -------------------------------------------------------------------------
1498    // Core Tactics
1499    // -------------------------------------------------------------------------
1500
1501    /// try_refl : Syntax -> Derivation
1502    ///
1503    /// Reflexivity tactic: given a goal, try to prove it by reflexivity.
1504    /// - If goal matches (Eq T a b) and a == b, returns DRefl T a
1505    /// - Otherwise returns DAxiom (SName "Error")
1506    /// Computational behavior defined in reduction.rs.
1507    fn register_try_refl(ctx: &mut Context) {
1508        let syntax = Term::Global("Syntax".to_string());
1509        let derivation = Term::Global("Derivation".to_string());
1510
1511        // try_refl : Syntax -> Derivation
1512        let try_refl_type = Term::Pi {
1513            param: "_".to_string(),
1514            param_type: Box::new(syntax),
1515            body_type: Box::new(derivation),
1516        };
1517
1518        ctx.add_declaration("try_refl", try_refl_type);
1519    }
1520
1521    /// try_compute : Syntax -> Derivation
1522    ///
1523    /// Computation tactic: given a goal (Eq T A B), proves it by evaluating
1524    /// both sides and checking equality.
1525    /// Returns DCompute goal.
1526    /// Computational behavior defined in reduction.rs.
1527    fn register_try_compute(ctx: &mut Context) {
1528        let syntax = Term::Global("Syntax".to_string());
1529        let derivation = Term::Global("Derivation".to_string());
1530
1531        // try_compute : Syntax -> Derivation
1532        let try_compute_type = Term::Pi {
1533            param: "_".to_string(),
1534            param_type: Box::new(syntax),
1535            body_type: Box::new(derivation),
1536        };
1537
1538        ctx.add_declaration("try_compute", try_compute_type);
1539    }
1540
1541    /// try_cong : Syntax -> Derivation -> Derivation
1542    ///
1543    /// Congruence tactic: given a context (SLam T body) and proof of (Eq T a b),
1544    /// produces proof of (Eq T (body[0:=a]) (body[0:=b])).
1545    /// Returns DCong context eq_proof.
1546    /// Computational behavior defined in reduction.rs.
1547    fn register_try_cong(ctx: &mut Context) {
1548        let syntax = Term::Global("Syntax".to_string());
1549        let derivation = Term::Global("Derivation".to_string());
1550
1551        // try_cong : Syntax -> Derivation -> Derivation
1552        let try_cong_type = Term::Pi {
1553            param: "_".to_string(),
1554            param_type: Box::new(syntax), // context
1555            body_type: Box::new(Term::Pi {
1556                param: "_".to_string(),
1557                param_type: Box::new(derivation.clone()), // eq_proof
1558                body_type: Box::new(derivation),
1559            }),
1560        };
1561
1562        ctx.add_declaration("try_cong", try_cong_type);
1563    }
1564
1565    // -------------------------------------------------------------------------
1566    // Tactic Combinators
1567    // -------------------------------------------------------------------------
1568
1569    /// tact_fail : Syntax -> Derivation
1570    ///
1571    /// A tactic that always fails by returning DAxiom (SName "Error").
1572    /// Useful for testing combinators and as a base case.
1573    /// Computational behavior defined in reduction.rs.
1574    fn register_tact_fail(ctx: &mut Context) {
1575        let syntax = Term::Global("Syntax".to_string());
1576        let derivation = Term::Global("Derivation".to_string());
1577
1578        // tact_fail : Syntax -> Derivation
1579        let tact_fail_type = Term::Pi {
1580            param: "_".to_string(),
1581            param_type: Box::new(syntax),
1582            body_type: Box::new(derivation),
1583        };
1584
1585        ctx.add_declaration("tact_fail", tact_fail_type);
1586    }
1587
1588    /// tact_orelse : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1589    ///
1590    /// Tactic combinator: try first tactic, if it fails (concludes to Error) try second.
1591    /// Enables composition of tactics with fallback behavior.
1592    /// Computational behavior defined in reduction.rs.
1593    fn register_tact_orelse(ctx: &mut Context) {
1594        let syntax = Term::Global("Syntax".to_string());
1595        let derivation = Term::Global("Derivation".to_string());
1596
1597        // Tactic type: Syntax -> Derivation
1598        let tactic_type = Term::Pi {
1599            param: "_".to_string(),
1600            param_type: Box::new(syntax.clone()),
1601            body_type: Box::new(derivation.clone()),
1602        };
1603
1604        // tact_orelse : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1605        let tact_orelse_type = Term::Pi {
1606            param: "_".to_string(),
1607            param_type: Box::new(tactic_type.clone()), // t1
1608            body_type: Box::new(Term::Pi {
1609                param: "_".to_string(),
1610                param_type: Box::new(tactic_type), // t2
1611                body_type: Box::new(Term::Pi {
1612                    param: "_".to_string(),
1613                    param_type: Box::new(syntax), // goal
1614                    body_type: Box::new(derivation),
1615                }),
1616            }),
1617        };
1618
1619        ctx.add_declaration("tact_orelse", tact_orelse_type);
1620    }
1621
1622    /// tact_try : (Syntax -> Derivation) -> Syntax -> Derivation
1623    ///
1624    /// Tactic combinator: try the tactic, but never fail.
1625    /// If the tactic fails (concludes to Error), return identity (DAxiom goal).
1626    /// Computational behavior defined in reduction.rs.
1627    fn register_tact_try(ctx: &mut Context) {
1628        let syntax = Term::Global("Syntax".to_string());
1629        let derivation = Term::Global("Derivation".to_string());
1630
1631        // Tactic type: Syntax -> Derivation
1632        let tactic_type = Term::Pi {
1633            param: "_".to_string(),
1634            param_type: Box::new(syntax.clone()),
1635            body_type: Box::new(derivation.clone()),
1636        };
1637
1638        // tact_try : (Syntax -> Derivation) -> Syntax -> Derivation
1639        let tact_try_type = Term::Pi {
1640            param: "_".to_string(),
1641            param_type: Box::new(tactic_type), // t
1642            body_type: Box::new(Term::Pi {
1643                param: "_".to_string(),
1644                param_type: Box::new(syntax),
1645                body_type: Box::new(derivation),
1646            }),
1647        };
1648
1649        ctx.add_declaration("tact_try", tact_try_type);
1650    }
1651
1652    /// tact_repeat : (Syntax -> Derivation) -> Syntax -> Derivation
1653    ///
1654    /// Tactic combinator: apply tactic repeatedly until it fails or makes no progress.
1655    /// Returns identity if tactic fails immediately.
1656    /// Computational behavior defined in reduction.rs.
1657    fn register_tact_repeat(ctx: &mut Context) {
1658        let syntax = Term::Global("Syntax".to_string());
1659        let derivation = Term::Global("Derivation".to_string());
1660
1661        // Tactic type: Syntax -> Derivation
1662        let tactic_type = Term::Pi {
1663            param: "_".to_string(),
1664            param_type: Box::new(syntax.clone()),
1665            body_type: Box::new(derivation.clone()),
1666        };
1667
1668        // tact_repeat : (Syntax -> Derivation) -> Syntax -> Derivation
1669        let tact_repeat_type = Term::Pi {
1670            param: "_".to_string(),
1671            param_type: Box::new(tactic_type), // t
1672            body_type: Box::new(Term::Pi {
1673                param: "_".to_string(),
1674                param_type: Box::new(syntax),
1675                body_type: Box::new(derivation),
1676            }),
1677        };
1678
1679        ctx.add_declaration("tact_repeat", tact_repeat_type);
1680    }
1681
1682    /// tact_then : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1683    ///
1684    /// Tactic combinator: sequence two tactics (the ";" operator).
1685    /// Apply t1 to goal, then apply t2 to the result.
1686    /// Fails if either tactic fails.
1687    /// Computational behavior defined in reduction.rs.
1688    fn register_tact_then(ctx: &mut Context) {
1689        let syntax = Term::Global("Syntax".to_string());
1690        let derivation = Term::Global("Derivation".to_string());
1691
1692        // Tactic type: Syntax -> Derivation
1693        let tactic_type = Term::Pi {
1694            param: "_".to_string(),
1695            param_type: Box::new(syntax.clone()),
1696            body_type: Box::new(derivation.clone()),
1697        };
1698
1699        // tact_then : (Syntax -> Derivation) -> (Syntax -> Derivation) -> Syntax -> Derivation
1700        let tact_then_type = Term::Pi {
1701            param: "_".to_string(),
1702            param_type: Box::new(tactic_type.clone()), // t1
1703            body_type: Box::new(Term::Pi {
1704                param: "_".to_string(),
1705                param_type: Box::new(tactic_type), // t2
1706                body_type: Box::new(Term::Pi {
1707                    param: "_".to_string(),
1708                    param_type: Box::new(syntax),
1709                    body_type: Box::new(derivation),
1710                }),
1711            }),
1712        };
1713
1714        ctx.add_declaration("tact_then", tact_then_type);
1715    }
1716
1717    /// tact_first : TList (Syntax -> Derivation) -> Syntax -> Derivation
1718    ///
1719    /// Tactic combinator: try tactics from a list until one succeeds.
1720    /// Returns Error if all tactics fail or list is empty.
1721    /// Computational behavior defined in reduction.rs.
1722    fn register_tact_first(ctx: &mut Context) {
1723        let syntax = Term::Global("Syntax".to_string());
1724        let derivation = Term::Global("Derivation".to_string());
1725
1726        // Tactic type: Syntax -> Derivation
1727        let tactic_type = Term::Pi {
1728            param: "_".to_string(),
1729            param_type: Box::new(syntax.clone()),
1730            body_type: Box::new(derivation.clone()),
1731        };
1732
1733        // TList (Syntax -> Derivation)
1734        let tactic_list_type = Term::App(
1735            Box::new(Term::Global("TList".to_string())),
1736            Box::new(tactic_type),
1737        );
1738
1739        // tact_first : TList (Syntax -> Derivation) -> Syntax -> Derivation
1740        let tact_first_type = Term::Pi {
1741            param: "_".to_string(),
1742            param_type: Box::new(tactic_list_type), // tactics
1743            body_type: Box::new(Term::Pi {
1744                param: "_".to_string(),
1745                param_type: Box::new(syntax),
1746                body_type: Box::new(derivation),
1747            }),
1748        };
1749
1750        ctx.add_declaration("tact_first", tact_first_type);
1751    }
1752
1753    /// tact_solve : (Syntax -> Derivation) -> Syntax -> Derivation
1754    ///
1755    /// Tactic combinator: tactic MUST completely solve the goal.
1756    /// If tactic returns Error, returns Error.
1757    /// If tactic returns a proof, returns that proof.
1758    /// Computational behavior defined in reduction.rs.
1759    fn register_tact_solve(ctx: &mut Context) {
1760        let syntax = Term::Global("Syntax".to_string());
1761        let derivation = Term::Global("Derivation".to_string());
1762
1763        // Tactic type: Syntax -> Derivation
1764        let tactic_type = Term::Pi {
1765            param: "_".to_string(),
1766            param_type: Box::new(syntax.clone()),
1767            body_type: Box::new(derivation.clone()),
1768        };
1769
1770        // tact_solve : (Syntax -> Derivation) -> Syntax -> Derivation
1771        let tact_solve_type = Term::Pi {
1772            param: "_".to_string(),
1773            param_type: Box::new(tactic_type), // t
1774            body_type: Box::new(Term::Pi {
1775                param: "_".to_string(),
1776                param_type: Box::new(syntax),
1777                body_type: Box::new(derivation),
1778            }),
1779        };
1780
1781        ctx.add_declaration("tact_solve", tact_solve_type);
1782    }
1783
1784    // -------------------------------------------------------------------------
1785    // Ring Tactic (Polynomial Equality)
1786    // -------------------------------------------------------------------------
1787
1788    /// DRingSolve : Syntax -> Derivation
1789    /// try_ring : Syntax -> Derivation
1790    ///
1791    /// Ring tactic: proves polynomial equalities by normalization.
1792    /// Computational behavior defined in reduction.rs.
1793    fn register_try_ring(ctx: &mut Context) {
1794        let syntax = Term::Global("Syntax".to_string());
1795        let derivation = Term::Global("Derivation".to_string());
1796
1797        // DRingSolve : Syntax -> Derivation
1798        // Proof constructor for ring-solved equalities
1799        ctx.add_constructor(
1800            "DRingSolve",
1801            "Derivation",
1802            Term::Pi {
1803                param: "_".to_string(),
1804                param_type: Box::new(syntax.clone()),
1805                body_type: Box::new(derivation.clone()),
1806            },
1807        );
1808
1809        // try_ring : Syntax -> Derivation
1810        // Ring tactic: given a goal, try to prove it by polynomial normalization
1811        let try_ring_type = Term::Pi {
1812            param: "_".to_string(),
1813            param_type: Box::new(syntax),
1814            body_type: Box::new(derivation),
1815        };
1816
1817        ctx.add_declaration("try_ring", try_ring_type);
1818    }
1819
1820    // -------------------------------------------------------------------------
1821    // LIA Tactic (Linear Integer Arithmetic)
1822    // -------------------------------------------------------------------------
1823
1824    /// DLiaSolve : Syntax -> Derivation
1825    /// try_lia : Syntax -> Derivation
1826    ///
1827    /// LIA tactic: proves linear inequalities by Fourier-Motzkin elimination.
1828    /// Computational behavior defined in reduction.rs.
1829    fn register_try_lia(ctx: &mut Context) {
1830        let syntax = Term::Global("Syntax".to_string());
1831        let derivation = Term::Global("Derivation".to_string());
1832
1833        // DLiaSolve : Syntax -> Derivation
1834        // Proof constructor for LIA-solved inequalities
1835        ctx.add_constructor(
1836            "DLiaSolve",
1837            "Derivation",
1838            Term::Pi {
1839                param: "_".to_string(),
1840                param_type: Box::new(syntax.clone()),
1841                body_type: Box::new(derivation.clone()),
1842            },
1843        );
1844
1845        // try_lia : Syntax -> Derivation
1846        // LIA tactic: given a goal, try to prove it by linear arithmetic
1847        let try_lia_type = Term::Pi {
1848            param: "_".to_string(),
1849            param_type: Box::new(syntax),
1850            body_type: Box::new(derivation),
1851        };
1852
1853        ctx.add_declaration("try_lia", try_lia_type);
1854    }
1855
1856    /// DccSolve : Syntax -> Derivation
1857    /// try_cc : Syntax -> Derivation
1858    ///
1859    /// Congruence Closure tactic: proves equalities over uninterpreted functions.
1860    /// Handles hypotheses via implications: (implies (Eq x y) (Eq (f x) (f y)))
1861    /// Computational behavior defined in reduction.rs.
1862    fn register_try_cc(ctx: &mut Context) {
1863        let syntax = Term::Global("Syntax".to_string());
1864        let derivation = Term::Global("Derivation".to_string());
1865
1866        // DccSolve : Syntax -> Derivation
1867        // Proof constructor for congruence closure proofs
1868        ctx.add_constructor(
1869            "DccSolve",
1870            "Derivation",
1871            Term::Pi {
1872                param: "_".to_string(),
1873                param_type: Box::new(syntax.clone()),
1874                body_type: Box::new(derivation.clone()),
1875            },
1876        );
1877
1878        // try_cc : Syntax -> Derivation
1879        // CC tactic: given a goal, try to prove it by congruence closure
1880        let try_cc_type = Term::Pi {
1881            param: "_".to_string(),
1882            param_type: Box::new(syntax),
1883            body_type: Box::new(derivation),
1884        };
1885
1886        ctx.add_declaration("try_cc", try_cc_type);
1887    }
1888
1889    /// DSimpSolve : Syntax -> Derivation
1890    /// try_simp : Syntax -> Derivation
1891    ///
1892    /// Simplifier tactic: proves equalities by term rewriting.
1893    /// Uses bottom-up rewriting with arithmetic evaluation and hypothesis substitution.
1894    /// Handles: reflexivity, constant folding (2+3=5), and hypothesis-based substitution.
1895    /// Computational behavior defined in reduction.rs.
1896    fn register_try_simp(ctx: &mut Context) {
1897        let syntax = Term::Global("Syntax".to_string());
1898        let derivation = Term::Global("Derivation".to_string());
1899
1900        // DSimpSolve : Syntax -> Derivation
1901        // Proof constructor for simplifier proofs
1902        ctx.add_constructor(
1903            "DSimpSolve",
1904            "Derivation",
1905            Term::Pi {
1906                param: "_".to_string(),
1907                param_type: Box::new(syntax.clone()),
1908                body_type: Box::new(derivation.clone()),
1909            },
1910        );
1911
1912        // try_simp : Syntax -> Derivation
1913        // Simp tactic: given a goal, try to prove it by simplification
1914        let try_simp_type = Term::Pi {
1915            param: "_".to_string(),
1916            param_type: Box::new(syntax),
1917            body_type: Box::new(derivation),
1918        };
1919
1920        ctx.add_declaration("try_simp", try_simp_type);
1921    }
1922
1923    /// DOmegaSolve : Syntax -> Derivation
1924    /// try_omega : Syntax -> Derivation
1925    ///
1926    /// Omega tactic: proves linear integer arithmetic with proper floor/ceil rounding.
1927    /// Unlike lia (which uses rationals), omega handles integers correctly:
1928    /// - x > 1 means x >= 2 (strict-to-nonstrict conversion)
1929    /// - 3x <= 10 means x <= 3 (floor division)
1930    /// Computational behavior defined in reduction.rs.
1931    fn register_try_omega(ctx: &mut Context) {
1932        let syntax = Term::Global("Syntax".to_string());
1933        let derivation = Term::Global("Derivation".to_string());
1934
1935        // DOmegaSolve : Syntax -> Derivation
1936        // Proof constructor for omega-solved inequalities
1937        ctx.add_constructor(
1938            "DOmegaSolve",
1939            "Derivation",
1940            Term::Pi {
1941                param: "_".to_string(),
1942                param_type: Box::new(syntax.clone()),
1943                body_type: Box::new(derivation.clone()),
1944            },
1945        );
1946
1947        // try_omega : Syntax -> Derivation
1948        // Omega tactic: given a goal, try to prove it by integer arithmetic
1949        let try_omega_type = Term::Pi {
1950            param: "_".to_string(),
1951            param_type: Box::new(syntax),
1952            body_type: Box::new(derivation),
1953        };
1954
1955        ctx.add_declaration("try_omega", try_omega_type);
1956    }
1957
1958    /// DAutoSolve : Syntax -> Derivation
1959    /// try_auto : Syntax -> Derivation
1960    ///
1961    /// Auto tactic: tries all decision procedures in sequence.
1962    /// Order: simp → ring → cc → omega → lia
1963    /// Returns the first successful derivation, or error if all fail.
1964    /// Computational behavior defined in reduction.rs.
1965    fn register_try_auto(ctx: &mut Context) {
1966        let syntax = Term::Global("Syntax".to_string());
1967        let derivation = Term::Global("Derivation".to_string());
1968
1969        // DAutoSolve : Syntax -> Derivation
1970        // Proof constructor for auto-solved goals
1971        ctx.add_constructor(
1972            "DAutoSolve",
1973            "Derivation",
1974            Term::Pi {
1975                param: "_".to_string(),
1976                param_type: Box::new(syntax.clone()),
1977                body_type: Box::new(derivation.clone()),
1978            },
1979        );
1980
1981        // try_auto : Syntax -> Derivation
1982        // Auto tactic: given a goal, try all tactics in sequence
1983        let try_auto_type = Term::Pi {
1984            param: "_".to_string(),
1985            param_type: Box::new(syntax),
1986            body_type: Box::new(derivation),
1987        };
1988
1989        ctx.add_declaration("try_auto", try_auto_type);
1990    }
1991
1992    /// try_induction : Syntax -> Syntax -> Derivation -> Derivation
1993    ///
1994    /// Generic induction tactic for any inductive type.
1995    /// Arguments:
1996    /// - ind_type: The inductive type (SName "Nat" or SApp (SName "List") A)
1997    /// - motive: The property to prove (SLam param_type body)
1998    /// - cases: DCase chain with one derivation per constructor
1999    ///
2000    /// Returns a DElim derivation if verification passes.
2001    fn register_try_induction(ctx: &mut Context) {
2002        let syntax = Term::Global("Syntax".to_string());
2003        let derivation = Term::Global("Derivation".to_string());
2004
2005        // try_induction : Syntax -> Syntax -> Derivation -> Derivation
2006        let try_induction_type = Term::Pi {
2007            param: "_".to_string(),
2008            param_type: Box::new(syntax.clone()), // ind_type
2009            body_type: Box::new(Term::Pi {
2010                param: "_".to_string(),
2011                param_type: Box::new(syntax.clone()), // motive
2012                body_type: Box::new(Term::Pi {
2013                    param: "_".to_string(),
2014                    param_type: Box::new(derivation.clone()), // cases
2015                    body_type: Box::new(derivation),
2016                }),
2017            }),
2018        };
2019
2020        ctx.add_declaration("try_induction", try_induction_type);
2021    }
2022
2023    /// Helper functions for building induction goals.
2024    ///
2025    /// These functions help construct the subgoals for induction:
2026    /// - induction_base_goal: Computes the base case goal
2027    /// - induction_step_goal: Computes the step case goal for a constructor
2028    /// - induction_num_cases: Returns number of constructors for an inductive
2029    fn register_induction_helpers(ctx: &mut Context) {
2030        let syntax = Term::Global("Syntax".to_string());
2031        let nat = Term::Global("Nat".to_string());
2032
2033        // induction_base_goal : Syntax -> Syntax -> Syntax
2034        // Given ind_type and motive, returns the base case goal (first constructor)
2035        ctx.add_declaration(
2036            "induction_base_goal",
2037            Term::Pi {
2038                param: "_".to_string(),
2039                param_type: Box::new(syntax.clone()),
2040                body_type: Box::new(Term::Pi {
2041                    param: "_".to_string(),
2042                    param_type: Box::new(syntax.clone()),
2043                    body_type: Box::new(syntax.clone()),
2044                }),
2045            },
2046        );
2047
2048        // induction_step_goal : Syntax -> Syntax -> Nat -> Syntax
2049        // Given ind_type, motive, constructor index, returns the case goal
2050        ctx.add_declaration(
2051            "induction_step_goal",
2052            Term::Pi {
2053                param: "_".to_string(),
2054                param_type: Box::new(syntax.clone()),
2055                body_type: Box::new(Term::Pi {
2056                    param: "_".to_string(),
2057                    param_type: Box::new(syntax.clone()),
2058                    body_type: Box::new(Term::Pi {
2059                        param: "_".to_string(),
2060                        param_type: Box::new(nat),
2061                        body_type: Box::new(syntax.clone()),
2062                    }),
2063                }),
2064            },
2065        );
2066
2067        // induction_num_cases : Syntax -> Nat
2068        // Returns number of constructors for an inductive type
2069        ctx.add_declaration(
2070            "induction_num_cases",
2071            Term::Pi {
2072                param: "_".to_string(),
2073                param_type: Box::new(syntax),
2074                body_type: Box::new(Term::Global("Nat".to_string())),
2075            },
2076        );
2077    }
2078
2079    // -------------------------------------------------------------------------
2080    // Inversion Tactic
2081    // -------------------------------------------------------------------------
2082
2083    /// try_inversion : Syntax -> Derivation
2084    ///
2085    /// Inversion tactic: given a hypothesis type, derives False if no constructor
2086    /// can possibly build that type.
2087    ///
2088    /// Example: try_inversion (SApp (SName "Even") three) proves False because
2089    /// neither even_zero (requires 0) nor even_succ (requires Even 1) can build Even 3.
2090    ///
2091    /// Computational behavior defined in reduction.rs.
2092    fn register_try_inversion_tactic(ctx: &mut Context) {
2093        let syntax = Term::Global("Syntax".to_string());
2094        let derivation = Term::Global("Derivation".to_string());
2095
2096        // try_inversion : Syntax -> Derivation
2097        ctx.add_declaration(
2098            "try_inversion",
2099            Term::Pi {
2100                param: "_".to_string(),
2101                param_type: Box::new(syntax),
2102                body_type: Box::new(derivation),
2103            },
2104        );
2105    }
2106
2107    // -------------------------------------------------------------------------
2108    // Operator Tactics (rewrite, destruct, apply)
2109    // -------------------------------------------------------------------------
2110
2111    /// Operator tactics for manual proof control.
2112    ///
2113    /// try_rewrite : Derivation -> Syntax -> Derivation
2114    /// try_rewrite_rev : Derivation -> Syntax -> Derivation
2115    /// try_destruct : Syntax -> Syntax -> Derivation -> Derivation
2116    /// try_apply : Syntax -> Derivation -> Syntax -> Derivation
2117    fn register_operator_tactics(ctx: &mut Context) {
2118        let syntax = Term::Global("Syntax".to_string());
2119        let derivation = Term::Global("Derivation".to_string());
2120
2121        // try_rewrite : Derivation -> Syntax -> Derivation
2122        // Given eq_proof (concluding Eq A x y) and goal, replaces x with y in goal
2123        ctx.add_declaration(
2124            "try_rewrite",
2125            Term::Pi {
2126                param: "_".to_string(),
2127                param_type: Box::new(derivation.clone()), // eq_proof
2128                body_type: Box::new(Term::Pi {
2129                    param: "_".to_string(),
2130                    param_type: Box::new(syntax.clone()), // goal
2131                    body_type: Box::new(derivation.clone()),
2132                }),
2133            },
2134        );
2135
2136        // try_rewrite_rev : Derivation -> Syntax -> Derivation
2137        // Given eq_proof (concluding Eq A x y) and goal, replaces y with x in goal (reverse direction)
2138        ctx.add_declaration(
2139            "try_rewrite_rev",
2140            Term::Pi {
2141                param: "_".to_string(),
2142                param_type: Box::new(derivation.clone()), // eq_proof
2143                body_type: Box::new(Term::Pi {
2144                    param: "_".to_string(),
2145                    param_type: Box::new(syntax.clone()), // goal
2146                    body_type: Box::new(derivation.clone()),
2147                }),
2148            },
2149        );
2150
2151        // try_destruct : Syntax -> Syntax -> Derivation -> Derivation
2152        // Case analysis without induction hypotheses
2153        ctx.add_declaration(
2154            "try_destruct",
2155            Term::Pi {
2156                param: "_".to_string(),
2157                param_type: Box::new(syntax.clone()), // ind_type
2158                body_type: Box::new(Term::Pi {
2159                    param: "_".to_string(),
2160                    param_type: Box::new(syntax.clone()), // motive
2161                    body_type: Box::new(Term::Pi {
2162                        param: "_".to_string(),
2163                        param_type: Box::new(derivation.clone()), // cases
2164                        body_type: Box::new(derivation.clone()),
2165                    }),
2166                }),
2167            },
2168        );
2169
2170        // try_apply : Syntax -> Derivation -> Syntax -> Derivation
2171        // Manual backward chaining - applies hypothesis to transform goal
2172        ctx.add_declaration(
2173            "try_apply",
2174            Term::Pi {
2175                param: "_".to_string(),
2176                param_type: Box::new(syntax.clone()), // hyp_name
2177                body_type: Box::new(Term::Pi {
2178                    param: "_".to_string(),
2179                    param_type: Box::new(derivation.clone()), // hyp_proof
2180                    body_type: Box::new(Term::Pi {
2181                        param: "_".to_string(),
2182                        param_type: Box::new(syntax), // goal
2183                        body_type: Box::new(derivation),
2184                    }),
2185                }),
2186            },
2187        );
2188    }
2189}