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
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
|
(* begin hide *)
Require Import Arith.
Require Import Nat.
Require Import Coq.Program.Equality. (* dependent induction *)
Require Import Lia.
(* end hide *)
(** The _weak call-by-value lambda calulus_ is a simple variant of
lambda calculus with simple abstractions and reduction rules. It
enjoys strong uniform-confluence properties and is easy to reason
with in machine proofs. *)
(** Like all lambda calculi, the language is built from variables,
applications and abstractions. *)
Inductive term :=
| var (n: nat)
| app (s: term) (t: term)
| lambda (s: term).
(** The substitution rule describes how the bound variable in an
abstraction is interpreted. The target variable increments up when
passing through an abstraction. *)
Fixpoint subst (s: term) (n: nat) (t: term) :=
match s with
| var i => match (eqb n i) with true => t | false => var i end
| app u v => app (subst u n t) (subst v n t)
| lambda u => lambda (subst u (S n) t)
end.
(** Terms are _closed_ if they are unaffected by substitutions. A
term is _bound_ by some [n] if it is unaffected by substitutions
of variables of size [n] or greater. *)
Fixpoint bound (s: term) (n: nat) : Prop :=
match s with
| var i => i < n
| app u v => (bound u n) /\ (bound v n)
| lambda u => bound u (S n)
end.
Definition closed (s: term) := bound s 0.
Definition variable (s: term) :=
exists (n: nat), s = var n.
Definition application (s: term) :=
exists (u v: term), s = app u v.
Definition abstraction (s: term) :=
exists (u: term), s = lambda u.
(** A _combinator_ (called a _procedure_ by Forster and Smolka) is a
closed abstraction. It is a function whose contents are not
changed by higher level substitutions. *)
Definition combinator (s: term) := closed s /\ abstraction s.
(** * Boundedness Properties
Below are some useful properties of boundedness. *)
Lemma bound_relaxes :
forall (s: term) (m n: nat),
m < n -> bound s m -> bound s n.
Proof.
intros s.
induction s as [k | u IHu v IHv | u IH].
- simpl. intros m n. intros Hmn Hkm.
apply Nat.lt_trans with (p := n) (n := k) (m := m).
apply Hkm. apply Hmn.
- intros m n. simpl. intros Hmn HumAvm.
destruct HumAvm as [Hum Hvm]. split.
apply IHu with (m := m) (n := n). apply Hmn. apply Hum.
apply IHv with (m := m) (n := n). apply Hmn. apply Hvm.
- intros m n Hmn. simpl. apply IH with (m := S m) (n := S n).
rewrite <- Nat.succ_lt_mono with (m := n) (n := m). apply Hmn.
Qed.
Lemma bound_subst :
forall (s t: term) (i n: nat),
bound s n -> bound t n -> bound (subst s i t) n.
Proof. intros s t. induction s as [j | u IHu v IHv | u IHu].
- simpl. intros i n Hij Hbound. destruct (i =? j).
+ apply Hbound. + simpl. apply Hij.
- intros i n. simpl. intros HunAvn Htn.
destruct HunAvn as [Hun Hvn]. split.
apply IHu. apply Hun. apply Htn.
apply IHv. apply Hvn. apply Htn.
- intros i n. simpl. intros HuSn Htn.
apply IHu with (i := S i) (n := S n).
apply HuSn. apply bound_relaxes with (m := n) (n := S n).
apply Nat.lt_succ_diag_r. apply Htn.
Qed.
Lemma subst_drops_bound :
forall (s t: term) (n: nat),
bound s (S n) -> bound t n -> bound (subst s n t) n.
Proof.
intros s t.
induction s as [k | u IHu v IHv | u IHu].
- intros n Hsbound Htbound. simpl. simpl in Hsbound.
destruct (n =? k) eqn:E.
* apply Htbound.
* rewrite Nat.lt_succ_r in Hsbound.
rewrite Nat.eqb_neq in E.
apply Nat.le_lteq in Hsbound.
destruct Hsbound.
{ simpl. apply H. }
{ unfold "<>" in E. apply eq_sym in H.
apply E in H. exfalso. apply H. }
- intros n Hsbound Htbound. simpl. simpl in Hsbound.
destruct Hsbound as [Hubound Hvbound]. split.
+ apply IHu. apply Hubound. apply Htbound.
+ apply IHv. apply Hvbound. apply Htbound.
- intros n. intros Hsbound Htbound. simpl. simpl in Hsbound.
apply IHu with (n := S n). apply Hsbound.
apply bound_relaxes with (m := n) (n := S n).
apply Nat.lt_succ_diag_r. apply Htbound.
Qed.
Lemma app_closed_iff :
forall (s t: term), closed (app s t) <-> closed s /\ closed t.
Proof. intros s t. unfold closed. simpl. split.
- intros H. apply H.
- intros H. apply H.
Qed.
Lemma subst_preserves_closed :
forall (u s t: term), s = lambda u -> closed s -> closed t ->
closed (subst u 0 t).
Proof.
induction u.
- intros s t Hsu Hsclosed Htclosed. simpl. destruct n.
+ apply Htclosed.
+ rewrite Hsu in Hsclosed. inversion Hsclosed.
apply Nat.leb_le in H0. simpl in H0. discriminate H0.
- intros s t Hsu Hsclosed Htclosed. simpl. apply app_closed_iff.
rewrite Hsu in Hsclosed. inversion Hsclosed as [Hu1 Hu2]. split.
+ apply IHu1 with (s := lambda u1). reflexivity. apply Hu1. apply Htclosed.
+ apply IHu2 with (s := lambda u2). reflexivity. apply Hu2. apply Htclosed.
- intros s t Hsu Hsclosed Htclosed. simpl. rewrite Hsu in Hsclosed.
unfold closed in Hsclosed. simpl in Hsclosed.
unfold closed. simpl.
apply subst_drops_bound. apply Hsclosed.
apply bound_relaxes with (m:=0) (n:=1).
apply Nat.lt_succ_diag_r. apply Htclosed.
Qed.
Lemma bounds_block_subst :
forall (s t: term) (k: nat), bound s k -> subst s k t = s.
Proof.
intros s. induction s.
- intros t k. simpl. intros Hbound. destruct (k =? n) eqn:E.
+ apply Nat.lt_neq in Hbound.
apply Nat.eqb_eq in E. apply Nat.eq_sym in E.
apply Hbound in E. exfalso. apply E.
+ reflexivity.
- intros t k Hbound. inversion Hbound as [Hs1bound Hs2bound]. simpl.
rewrite IHs1. rewrite IHs2. reflexivity. apply Hs2bound. apply Hs1bound.
- intros t k Hbound. simpl in Hbound. simpl.
rewrite IHs. reflexivity. apply Hbound.
Qed.
(** * Simple Combinators
Below are some examples of simple combinators written in the weak
call-by-value language.
- [I]: identity
- [T]: true branch (returns first of two inputs)
- [F]: false branch (returns second of two inputs)
- [omega]: self-applicator
- [Omega]: infinite loop
*)
Definition c_I := lambda (var 0).
Definition c_T := lambda (lambda (var 1)).
Definition c_F := lambda (lambda (var 0)).
Definition c_omega := lambda (app (var 0) (var 0)).
Definition c_Omega := lambda (app c_omega c_omega).
(** * Reflections
It is helpful in several proofs to have reflections of equality,
boundedness, closure and combinators as boolean methods. They are
included below. *)
(** ** Equality *)
Fixpoint term_eqb (x: term) (y: term) :=
match x with
| var i => match y with
| var j => (eqb i j)
| _ => false
end
| app ux vx => match y with
| app uy vy => andb (term_eqb ux uy) (term_eqb vx vy)
| _ => false
end
| lambda ux => match y with
| lambda uy => term_eqb ux uy
| _ => false
end
end.
Ltac absurd := simpl; intros H; inversion H.
Lemma term_eqb_compat :
forall (x y: term), term_eqb x y = true <-> x = y.
Proof.
induction x.
- destruct y.
+ simpl. rewrite PeanoNat.Nat.eqb_eq.
split.
* intros H. rewrite H. reflexivity.
*intros H. injection H as Heq. apply Heq.
+ simpl. split. absurd. absurd.
+ simpl. split. absurd. absurd.
- destruct y.
+ simpl. split. absurd. absurd.
+ simpl. split.
* intros Heq.
apply eq_sym in Heq. apply Bool.andb_true_eq in Heq.
destruct Heq as [H1 H2].
apply eq_sym in H1. apply IHx1 in H1. rewrite H1.
apply eq_sym in H2. apply IHx2 in H2. rewrite H2.
reflexivity.
* intros Heq. inversion Heq. rewrite <- H0. rewrite <- H1.
apply andb_true_intro. split.
{ apply IHx1. reflexivity. } { apply IHx2. reflexivity. }
+ simpl. split. absurd. absurd.
- destruct y.
+ simpl. split. absurd. absurd.
+ simpl. split. absurd. absurd.
+ simpl. rewrite IHx. split.
* intros H. rewrite H. reflexivity.
* intros H. injection H as Heq. apply Heq.
Qed.
(** ** Boundedness *)
Fixpoint is_bound (x: term) (n: nat) :=
match x with
| var i => ltb i n
| app u v => andb (is_bound u n) (is_bound v n)
| lambda u => is_bound u (S n)
end.
Lemma is_bound_compat :
forall (x: term) (n: nat), is_bound x n = true <-> bound x n.
Proof.
induction x as [k | u Hu v Hv | u Hu].
- intros n. simpl. apply PeanoNat.Nat.ltb_lt.
- intros n. simpl. rewrite <- Hu. rewrite <- Hv.
apply Bool.andb_true_iff.
- intros n. simpl. rewrite <- Hu. apply iff_refl.
Qed.
(** ** Closure *)
Definition is_closed (x: term) := is_bound x 0.
Corollary is_closed_compat :
forall (x: term), is_closed x = true <-> closed x.
Proof.
unfold is_closed. unfold closed. intros x.
apply is_bound_compat.
Qed.
(** ** Abstraction *)
Definition is_abstraction (x: term) : bool :=
match x with
| lambda u => true
| _ => false
end.
Lemma is_abstraction_compat :
forall (x: term), is_abstraction x = true <-> abstraction x.
Proof.
destruct x.
- simpl. split.
+ intros H. inversion H.
+ intros H. inversion H as [u Hu]. inversion Hu.
- simpl. split.
+ intros H. inversion H.
+ intros H. inversion H as [u Hu]. inversion Hu.
- simpl. split.
+ intros _. exists x. reflexivity.
+ reflexivity.
Qed.
(** ** Combinator *)
Definition is_combinator (x: term) :=
andb (is_abstraction x) (is_closed x).
Lemma is_combinator_compat :
forall (x: term), is_combinator x = true <-> combinator x.
Proof.
intros x. unfold is_combinator. unfold combinator.
rewrite <- is_closed_compat. rewrite <- is_abstraction_compat.
rewrite Bool.andb_comm. apply Bool.andb_true_iff.
Qed.
(** ** Substitution *)
Definition predicate (x: term) :=
match x with
| lambda u => u
| _ => x
end.
Definition combine (f x: term) := subst (predicate f) 0 x.
|