aboutsummaryrefslogtreecommitdiff
path: root/theories/L.v
diff options
context:
space:
mode:
Diffstat (limited to 'theories/L.v')
-rw-r--r--theories/L.v321
1 files changed, 321 insertions, 0 deletions
diff --git a/theories/L.v b/theories/L.v
new file mode 100644
index 0000000..e9b8417
--- /dev/null
+++ b/theories/L.v
@@ -0,0 +1,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.