-
Notifications
You must be signed in to change notification settings - Fork 43
/
Copy pathclosed_terms.v
219 lines (171 loc) · 8.54 KB
/
closed_terms.v
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
Require Import
Coq.Classes.RelationClasses Coq.Relations.Relation_Definitions Coq.Lists.List Coq.Classes.Morphisms
MathClasses.interfaces.universal_algebra MathClasses.theory.ua_homomorphisms
MathClasses.interfaces.abstract_algebra MathClasses.interfaces.canonical_names
MathClasses.theory.categories MathClasses.categories.varieties.
Section contents.
Variable et: EquationalTheory.
(* The initial object will consists of arity-0 terms with a congruence incorporating the variety's laws.
For this we simply take universal_algebra's Term type, but exclude variables by taking False
as the variable index type: *)
Let ClosedTerm := (Term et False).
Let ClosedTerm0 a := ClosedTerm (ne_list.one a).
(* Operations are implemented as App-tree builders, so that [o a b] yields [App (App (Op o) a) b]. *)
Fixpoint app_tree {o}: ClosedTerm o → op_type ClosedTerm0 o :=
match o with
| ne_list.one _ => id
| ne_list.cons _ _ => λ x y, app_tree (App _ _ _ _ x y)
end.
Instance: AlgebraOps et ClosedTerm0 := λ x, app_tree (Op _ _ x).
(* We define term equivalence on all operation types: *)
Inductive e: ∀ o, Equiv (ClosedTerm o) :=
| e_refl o: Reflexive (e o)
| e_trans o: Transitive (e o)
| e_sym o: Symmetric (e o)
| e_sub o h: Proper ((=) ==> (=) ==> (=)) (App _ _ h o)
| e_law (s: EqEntailment et): et_laws et s → ∀ (v: Vars et ClosedTerm0 nat),
(∀ x, In x (entailment_premises _ s) → eval et v (fst (projT2 x)) = eval et v (snd (projT2 x))) →
eval et v (fst (projT2 (entailment_conclusion _ s))) = eval et v (snd (projT2 (entailment_conclusion _ s))).
Existing Instance e.
Existing Instance e_refl.
Existing Instance e_sym.
Existing Instance e_trans.
(* .. and then take the specialization at arity 0 for Term0: *)
Instance: ∀ a, Equiv (ClosedTerm0 a) := λ a, e (ne_list.one a).
Instance: ∀ a, Setoid (ClosedTerm0 a).
Proof. split; apply _. Qed.
(* While this fancy congruence is the one we'll use to make our initial object a setoid,
in our proofs we will also need to talk about extensionally equal closed term
builders (i.e. terms of type [op_type ClosedTerm0 a] for some a), where we use /Leibniz/ equality
on closed terms: *)
Let structural_eq a: relation _ := @op_type_equiv (sorts et) ClosedTerm0 (λ _, eq) a.
Instance structural_eq_refl a: Reflexive (structural_eq a).
Proof. induction a; repeat intro. reflexivity. subst. apply IHa. Qed.
(* The implementation is proper: *)
Instance app_tree_proper: ∀ o, Proper ((=) ==> (=)) (@app_tree o).
Proof with auto.
induction o; repeat intro...
apply IHo, e_sub...
Qed.
Instance: Algebra et ClosedTerm0.
Proof.
constructor. intro. apply _.
intro. apply app_tree_proper. reflexivity.
Qed.
(* hm, this isn't "the" (closed) term algebra, because we used equivalence modulo an equational theory *)
(* Better still, the laws hold: *)
Lemma laws_hold s (L: et_laws et s): ∀ vars, eval_stmt _ vars s.
Proof with simpl in *; intuition.
intros.
rewrite boring_eval_entailment.
destruct s. simpl in *. intros.
apply (e_law _ L vars). clear L.
induction entailment_premises... subst...
Qed.
(* Hence, we have a variety: *)
Global Instance: InVariety et ClosedTerm0.
Proof. constructor. apply _. intros. apply laws_hold. assumption. Qed.
(* And hence, an object in the category: *)
Definition the_object: varieties.Object et := varieties.object et ClosedTerm0.
(* Interestingly, this object is initial, which we prove in the remainder of this file. *)
(* To show its initiality, we begin by constructing arrows to arbitrary other objects: *)
Section for_another_object.
Variable other: varieties.Object et.
(* Computationally, the arrow simply evaluates closed terms in the other
model. For induction purposes, we first define this for arbitrary op_types: *)
Definition eval_in_other {o}: ClosedTerm o → op_type other o := @eval et other _ False o (no_vars _ other).
Definition morph a: the_object a → other a := eval_in_other.
(* Given an assignment mapping variables to closed terms of arity 0, we can now
evaluate open terms in the other model in two ways: by first closing it and then
evaluating the closed term using eval_in_other, or by evaluating it directly but
with variable lookup implemented in terms of eval_in_other. We now show that
these two ways yield the same result, thanks to proper-ness of the algebra's
operations: *)
Lemma subst_eval o V (v: Vars _ ClosedTerm0 _) (t: Term _ V o):
@eval _ other _ _ _ (λ x y, eval_in_other (v x y)) t =
eval_in_other (close _ v t).
Proof.
induction t; simpl.
reflexivity.
apply IHt1. auto.
apply (@algebra_propers et other _ _ _ o).
Qed. (* todo: rename *)
(* On the side of the_object, evaluating a term of arity 0 is the same as closing it: *)
Lemma eval_is_close V x v (t: Term0 et V x): eval et v t ≡ close _ v t.
Proof with auto; try reflexivity.
pattern x, t.
apply applications_rect; simpl...
intro.
cut (@equiv _ (structural_eq _) (app_tree (close _ v (Op et _ o))) (eval et v (Op et _ o)))...
generalize (Op et V o).
induction (et o); simpl...
intros ? H ? E. apply IHo0. simpl. rewrite E. apply H...
Qed.
(* And with those two somewhat subtle lemmas, we show that eval_in_other is a setoid morphism: *)
Instance prep_proper {o}: Proper ((=) ==> (=)) (@eval_in_other o).
Proof with intuition.
intros x y H.
induction H; simpl...
induction x; simpl...
apply IHx1...
apply (@algebra_propers et other _ _ _ o).
apply IHe...
unfold Vars in v.
pose proof (@variety_laws et other _ _ _ s H (λ a n, eval_in_other (v a n))) as Q.
clear H.
destruct s.
rewrite boring_eval_entailment in Q.
simpl in *.
do 2 rewrite eval_is_close.
do 2 rewrite <- subst_eval.
apply Q. clear Q.
induction entailment_premises; simpl...
do 2 rewrite subst_eval.
do 2 rewrite <- eval_is_close...
Qed.
Instance: ∀ a, Setoid_Morphism (@eval_in_other (ne_list.one a)).
Proof. constructor; simpl; try apply _. Qed.
(* Furthermore, we can show preservation of operations, giving us a homomorphism (and an arrow): *)
Instance: @HomoMorphism et ClosedTerm0 other _ (varieties.variety_equiv et other) _ _ (λ _, eval_in_other).
Proof with intuition.
constructor; try apply _.
intro.
change (Preservation et ClosedTerm0 other (λ _, eval_in_other) (app_tree (Op _ _ o)) (varieties.variety_ops _ other o)).
generalize (algebra_propers o : eval_in_other (Op _ _ o) = varieties.variety_ops _ other o).
generalize (Op _ False o) (varieties.variety_ops et other o).
induction (et o)...
simpl. intro. apply IHo0, H.
apply reflexivity. (* todo: shouldn't have to say [apply] here. file bug *)
Qed.
Program Definition the_arrow: the_object ⟶ other := λ _, eval_in_other.
(* All that remains is to show that this arrow is unique: *)
Theorem arrow_unique: ∀ y, the_arrow = y.
Proof with auto; try intuition.
intros [x h] b a.
simpl in *.
pattern b, a.
apply applications_rect...
pose proof (@preserves et ClosedTerm0 other _ _ _ _ x h o).
change (Preservation et ClosedTerm0 other x (app_tree (Op _ _ o)) (@eval_in_other _ (Op _ _ o))) in H.
revert H.
generalize (Op _ False o).
induction (et o); simpl...
apply IHo0.
simpl in *.
assert (app_tree (App _ _ o0 t t0 v) = app_tree (App _ _ o0 t t0 v)).
apply app_tree_proper...
apply (@Preservation_proper et ClosedTerm0 other _ _ x _ _ _ o0
(app_tree (App _ _ o0 t t0 v)) (app_tree (App _ _ o0 t t0 v)) H1
(eval_in_other t0 (eval_in_other v)) (eval_in_other t0 (x t v)))...
pose proof (@prep_proper _ t0 t0 (reflexivity _))... (* todo: why doesn't rewrite work here? *)
Qed. (* todo: needs further cleanup *)
End for_another_object.
Hint Extern 4 (InitialArrow the_object) => exact the_arrow: typeclass_instances.
Instance: Initial the_object.
Proof. intro. apply arrow_unique. Qed.
(* Todo: Show decidability of equality (likely quite tricky). Without that, we cannot use any of this to
get a canonical model of the naturals/integers, because such models must be decidable. *)
(* (Tom): This is possible in the general case, since that would involve solving the word problem for
groups. In particular, a group presentation determines a variety, the initial object of which is the
group so presented. *)
End contents.