Require Export Tactics.

Scott encoding of numbers


Fixpoint enc (n : nat) :=
  match n with
  | 0 => lambda(lambda (1))
  | S n => lambda(lambda ( 0 (enc n)))
  end.

Lemma enc_proc m :
  proc (enc m).
Proof.
  induction m; value.
Qed.

Hint Resolve enc_proc : cbv.

Lemma enc_injective m n : enc m = enc n -> m = n.
Proof.
  revert n; induction m; intros n; destruct n; inversion 1; eauto.
Qed.

Lemma enc_inj m n : enc m enc n -> m = n.
Proof.
  intros. destruct (enc_proc m) as [? []], (enc_proc n) as [? []]. rewrite H1, H3 in H.
  eapply unique_normal_forms in H; value. subst. eapply enc_injective; congruence.
Qed.

Definition Zero : term := .\"z","s"; "z".
Definition Succ : term := .\"n","z","s"; "s" "n".

Hint Unfold Zero Succ : cbv.

Lemma Succ_correct n : Succ (enc n) ≻* enc (S n).
Proof.
  solvered.
Qed.

Definition Add := Eval cbn in rho (.\ "a", "n", "m"; "n" "m" (.\"n"; !Succ ("a" "n" "m"))).

Hint Unfold Add : cbv.

Lemma Add_correct n m :
  Add (enc n) (enc m) enc (n + m).
Proof.
  induction n; solveeq.
Qed.

Scott encoding of terms


Fixpoint tenc t :=
  lambda ( (* var *) lambda ( (* app *) lambda ( (* lambda *)
     match t with
       | var n => (var 2) (enc n)
       | app s t => (var 1) (tenc s) (tenc t)
       | lambda s => (var 0) (tenc s)
     end
  ))).

Lemma tenc_proc s : proc (tenc s).
Proof.
  induction s; value.
Qed.

Hint Resolve tenc_proc : cbv.

Lemma tenc_injective s t : tenc s = tenc t -> s = t.
Proof.
  revert t; induction s; intros t; destruct t; inversion 1.
  - eauto using enc_injective.
  - erewrite IHs1, IHs2; eauto.
  - erewrite IHs; eauto.
Qed.

Lemma tenc_inj s t : tenc s tenc t -> s = t.
Proof.
  intros. destruct (tenc_proc t) as [? []], (tenc_proc s) as [? []]. rewrite H1, H3 in H.
  eapply unique_normal_forms in H; value. eapply tenc_injective. congruence.
Qed.

Definition Var : term := .\"n"; .\"v","a","l"; "v" "n".
Definition App : term := .\"s","t"; .\"v","a","l"; "a" "s" "t".
Definition Lam : term := .\"s"; .\"v","a","l"; "l" "s".

Lemma Var_correct n : Var (enc n) tenc (n).
Proof.
  solveeq.
Qed.

Lemma App_correct s t : App (tenc s) (tenc t) tenc (s t).
Proof.
  solveeq.
Qed.

Lemma Lam_correct s : Lam (tenc s) tenc (lambda s).
Proof.
  solveeq.
Qed.

Definition N := rho ( .\"N", "n"; "n"
   !(tenc Zero)
   (.\"n"; !Lam (!Lam (!App !(tenc 0) ("N" "n"))))).

Lemma N_correct n : N (enc n) tenc(enc n).
Proof.
  induction n; solveeq.
Qed.

Definition Q := Eval cbn in rho ( .\"Q", "s"; "s"
   (.\"n"; !Lam (!Lam (!Lam (!App !(tenc 2) (!N "n")))))
   (.\"s","t"; !Lam (!Lam (!Lam (!App (!App !(tenc 1) ("Q" "s")) ("Q" "t")))))
   (.\"s"; !Lam (!Lam (!Lam (!App !(tenc 0) ("Q" "s"))))) ).

Lemma Q_correct s : Q (tenc s) tenc(tenc s).
Proof.
  induction s; (try assert (R:=N_correct n)); solveeq.
Qed.

Scott encoding of booleans


Definition benc (b:bool) : term := if b then T else F.
Hint Unfold T F : cbv.

Lemma benc_proc b : proc (benc b).
Proof.
  destruct b; value.
Qed.
Hint Resolve benc_proc : cbv.

Lemma T_equiv_F : ~ T F.
Proof.
  cbv. intros H. eapply unique_normal_forms in H; value. inv H.
Qed.