From Coq Require Import Relations.Relations Classes.RelationClasses. From Tealeaves Require Import Backends.DB. Import DecoratedTraversableMonad.UsefulInstances. #[local] Set Implicit Arguments. Import DB.Notations. Inductive lam (V: Type) := | tvar: V -> lam V | abs: lam V -> lam V | app: lam V -> lam V -> lam V. Fixpoint binddt_lam (G: Type -> Type) `{Map G} `{Pure G} `{Mult G} {v1 v2: Type} (f: nat * v1 -> G (lam v2)) (t: lam v1): G (lam v2) := match t with | tvar v => f (0, v) | abs body => pure (@abs v2) <⋆> binddt_lam (f ⦿ 1) body | app t1 t2 => pure (@app v2) <⋆> binddt_lam f t1 <⋆> binddt_lam f t2 end. #[export] Instance Return_Lam: Return lam := tvar. #[export] Instance Binddt_Lam: Binddt nat lam lam := @binddt_lam.DecoratedTraversableMonad nat lamderive_dtm. Qed.DecoratedTraversableMonad nat lamDecoratedTraversableMonad nat lamDecoratedTraversableMonad nat lamMonoid natforall (G : Type -> Type) (Map_G : Map G) (Pure_G : Pure G) (Mult_G : Mult G), Applicative G -> forall (A B : Type) (f : nat * A -> G (lam B)), binddt f ∘ ret = f ∘ retDecoratedTraversableRightPreModule nat lam lamtypeclasses eauto.Monoid natforall (G : Type -> Type) (Map_G : Map G) (Pure_G : Pure G) (Mult_G : Mult G), Applicative G -> forall (A B : Type) (f : nat * A -> G (lam B)), binddt f ∘ ret = f ∘ retreflexivity.G: Type -> Type
Map_G: Map G
Pure_G: Pure G
Mult_G: Mult G
H: Applicative G
A, B: Type
f: nat * A -> G (lam B)binddt f ∘ ret = f ∘ retDecoratedTraversableRightPreModule nat lam lamforall A : Type, binddt (ret ∘ extract) = idforall (G1 : Type -> Type) (Map_G : Map G1) (Pure_G : Pure G1) (Mult_G : Mult G1), Applicative G1 -> forall (G2 : Type -> Type) (Map_G0 : Map G2) (Pure_G0 : Pure G2) (Mult_G0 : Mult G2), Applicative G2 -> forall (B C : Type) (g : nat * B -> G2 (lam C)) (A : Type) (f : nat * A -> G1 (lam B)), map (binddt g) ∘ binddt f = binddt (g ⋆7 f)forall (G1 G2 : Type -> Type) (H : Map G1) (H0 : Mult G1) (H1 : Pure G1) (H2 : Map G2) (H3 : Mult G2) (H4 : Pure G2) (ϕ : forall A : Type, G1 A -> G2 A), ApplicativeMorphism G1 G2 ϕ -> forall (A B : Type) (f : nat * A -> G1 (lam B)), ϕ (lam B) ∘ binddt f = binddt (ϕ (lam B) ∘ f)forall A : Type, binddt (ret ∘ extract) = idA: Typebinddt (ret ∘ extract) = idA: Type
t: lam Abinddt (ret ∘ extract) t = id tA: Type
v: Abinddt (ret ∘ extract) (tvar v) = id (tvar v)A: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tbinddt (ret ∘ extract) (abs t) = id (abs t)A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2binddt (ret ∘ extract) (app t1 t2) = id (app t1 t2)reflexivity.A: Type
v: Abinddt (ret ∘ extract) (tvar v) = id (tvar v)A: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tbinddt (ret ∘ extract) (abs t) = id (abs t)A: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tpure (abs (V:=A)) (binddt ((ret ∘ extract) ⦿ 1) t) = id (abs t)A: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tpure (abs (V:=A)) (binddt ((ret ∘ extract) ⦿ 1) t) = abs tA: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tabs (binddt ((ret ∘ extract) ⦿ 1) t) = abs tA: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tabs (binddt (ret ∘ extract) t) = abs treflexivity.A: Type
t: lam A
IHt: binddt (ret ∘ extract) t = id tabs (id t) = abs tA: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2binddt (ret ∘ extract) (app t1 t2) = id (app t1 t2)A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2pure (app (V:=A)) (binddt (ret ∘ extract) t1) (binddt (ret ∘ extract) t2) = id (app t1 t2)A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2pure (app (V:=A)) (binddt (ret ∘ extract) t1) (binddt (ret ∘ extract) t2) = app t1 t2A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2app (binddt (ret ∘ extract) t1) (binddt (ret ∘ extract) t2) = app t1 t2A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2app (id t1) (binddt (ret ∘ extract) t2) = app t1 t2reflexivity.A: Type
t1, t2: lam A
IHt1: binddt (ret ∘ extract) t1 = id t1
IHt2: binddt (ret ∘ extract) t2 = id t2app (id t1) (id t2) = app t1 t2forall (G1 : Type -> Type) (Map_G : Map G1) (Pure_G : Pure G1) (Mult_G : Mult G1), Applicative G1 -> forall (G2 : Type -> Type) (Map_G0 : Map G2) (Pure_G0 : Pure G2) (Mult_G0 : Mult G2), Applicative G2 -> forall (B C : Type) (g : nat * B -> G2 (lam C)) (A : Type) (f : nat * A -> G1 (lam B)), map (binddt g) ∘ binddt f = binddt (g ⋆7 f)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C: Type
g: nat * B -> G2 (lam C)
A: Type
f: nat * A -> G1 (lam B)map (binddt g) ∘ binddt f = binddt (g ⋆7 f)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C: Type
g: nat * B -> G2 (lam C)
A: Type
f: nat * A -> G1 (lam B)
t: lam A(map (binddt g) ∘ binddt f) t = binddt (g ⋆7 f) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C: Type
g: nat * B -> G2 (lam C)
A: Type
f: nat * A -> G1 (lam B)
t: lam Amap (binddt g) (binddt f t) = binddt (g ⋆7 f) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C: Type
g: nat * B -> G2 (lam C)
A: Type
t: lam Aforall f : nat * A -> G1 (lam B), map (binddt g) (binddt f t) = binddt (g ⋆7 f) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam Aforall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
v: A
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (tvar v)) = binddt (g ⋆7 f) (tvar v)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (abs t)) = binddt (g ⋆7 f) (abs t)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (app t1 t2)) = binddt (g ⋆7 f) (app t1 t2)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
v: A
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (tvar v)) = binddt (g ⋆7 f) (tvar v)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
v: A
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (f (0, v)) = map (binddt (g ⦿ 0)) (f (0, v))G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
v: A
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (f (Ƶ : nat, v)) = map (binddt (g ⦿ (Ƶ : nat))) (f (Ƶ : nat, v))reflexivity.G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
v: A
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (f (Ƶ, v)) = map (binddt g) (f (Ƶ, v))G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (abs t)) = binddt (g ⋆7 f) (abs t)(* LHS *)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (pure (abs (V:=B)) <⋆> binddt (f ⦿ 1) t) = pure (abs (V:=C)) <⋆> binddt ((g ⋆7 f) ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (compose (binddt g)) (pure (abs (V:=B))) <⋆> binddt (f ⦿ 1) t = pure (abs (V:=C)) <⋆> binddt ((g ⋆7 f) ⦿ 1) t(* RHS *)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (abs (V:=C)) <⋆> binddt ((g ⋆7 f) ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (pure (abs (V:=C))) <⋆> binddt ((g ⋆7 f) ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = map (ap G2) (pure (pure (abs (V:=C)))) <⋆> binddt ((g ⋆7 f) ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (ap G2 (pure (abs (V:=C)))) <⋆> binddt ((g ⋆7 f) ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (ap G2 (pure (abs (V:=C)))) <⋆> binddt (g ⦿ 1 ⋆7 f ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (ap G2 (pure (abs (V:=C)))) <⋆> map (binddt (g ⦿ 1)) (binddt (f ⦿ 1) t)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = map (precompose (binddt (g ⦿ 1))) (pure (ap G2 (pure (abs (V:=C))))) <⋆> binddt (f ⦿ 1) treflexivity.G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t: lam A
IHt: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t) = binddt (g ⋆7 f) t
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (binddt g ∘ abs (V:=B)) <⋆> binddt (f ⦿ 1) t = pure (precompose (binddt (g ⦿ 1)) (ap G2 (pure (abs (V:=C))))) <⋆> binddt (f ⦿ 1) tG1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (binddt f (app t1 t2)) = binddt (g ⋆7 f) (app t1 t2)(* LHS *)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (binddt g) (pure (app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2) = pure (app (V:=C)) <⋆> binddt (g ⋆7 f) t1 <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (compose (binddt g)) (pure (app (V:=B)) <⋆> binddt f t1) <⋆> binddt f t2 = pure (app (V:=C)) <⋆> binddt (g ⋆7 f) t1 <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)map (compose (compose (binddt g))) (pure (app (V:=B))) <⋆> binddt f t1 <⋆> binddt f t2 = pure (app (V:=C)) <⋆> binddt (g ⋆7 f) t1 <⋆> binddt (g ⋆7 f) t2(* RHS *) (* IHt1 *)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (app (V:=C)) <⋆> binddt (g ⋆7 f) t1 <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (app (V:=C)) <⋆> map (binddt g) (binddt f t1) <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (pure (app (V:=C))) <⋆> map (binddt g) (binddt f t1) <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (ap G2) (pure (pure (app (V:=C)))) <⋆> map (binddt g) (binddt f t1) <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (ap G2 (pure (app (V:=C)))) <⋆> map (binddt g) (binddt f t1) <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (precompose (binddt g)) (pure (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1 <⋆> binddt (g ⋆7 f) t2(* IHt2 *)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (precompose (binddt g) (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1 <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (ap G2) (pure (precompose (binddt g) (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1) <⋆> binddt (g ⋆7 f) t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (ap G2) (pure (precompose (binddt g) (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1) <⋆> map (binddt g) (binddt f t2)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (compose (ap G2)) (pure (precompose (binddt g) (ap G2 (pure (app (V:=C)))))) <⋆> binddt f t1 <⋆> map (binddt g) (binddt f t2)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (ap G2 ∘ precompose (binddt g) (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1 <⋆> map (binddt g) (binddt f t2)G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (precompose (binddt g)) (pure (ap G2 ∘ precompose (binddt g) (ap G2 (pure (app (V:=C))))) <⋆> binddt f t1) <⋆> binddt f t2G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = map (compose (precompose (binddt g))) (pure (ap G2 ∘ precompose (binddt g) (ap G2 (pure (app (V:=C)))))) <⋆> binddt f t1 <⋆> binddt f t2reflexivity.G1: Type -> Type
Map_G: Map G1
Pure_G: Pure G1
Mult_G: Mult G1
H: Applicative G1
G2: Type -> Type
Map_G0: Map G2
Pure_G0: Pure G2
Mult_G0: Mult G2
H0: Applicative G2
B, C, A: Type
t1, t2: lam A
IHt1: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t1) = binddt (g ⋆7 f) t1
IHt2: forall (g : nat * B -> G2 (lam C)) (f : nat * A -> G1 (lam B)), map (binddt g) (binddt f t2) = binddt (g ⋆7 f) t2
g: nat * B -> G2 (lam C)
f: nat * A -> G1 (lam B)pure (compose (binddt g) ∘ app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2 = pure (precompose (binddt g) ∘ (ap G2 ∘ precompose (binddt g) (ap G2 (pure (app (V:=C)))))) <⋆> binddt f t1 <⋆> binddt f t2forall (G1 G2 : Type -> Type) (H : Map G1) (H0 : Mult G1) (H1 : Pure G1) (H2 : Map G2) (H3 : Mult G2) (H4 : Pure G2) (ϕ : forall A : Type, G1 A -> G2 A), ApplicativeMorphism G1 G2 ϕ -> forall (A B : Type) (f : nat * A -> G1 (lam B)), ϕ (lam B) ∘ binddt f = binddt (ϕ (lam B) ∘ f)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
f: nat * A -> G1 (lam B)ϕ (lam B) ∘ binddt f = binddt (ϕ (lam B) ∘ f)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
f: nat * A -> G1 (lam B)
t: lam A(ϕ (lam B) ∘ binddt f) t = binddt (ϕ (lam B) ∘ f) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
f: nat * A -> G1 (lam B)
t: lam Aϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam Aforall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
v: A
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (tvar v)) = binddt (ϕ (lam B) ○ f) (tvar v)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (abs t)) = binddt (ϕ (lam B) ○ f) (abs t)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (app t1 t2)) = binddt (ϕ (lam B) ○ f) (app t1 t2)reflexivity.G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
v: A
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (tvar v)) = binddt (ϕ (lam B) ○ f) (tvar v)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (abs t)) = binddt (ϕ (lam B) ○ f) (abs t)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)ϕ (lam B) (pure (abs (V:=B)) <⋆> binddt (f ⦿ 1) t) = pure (abs (V:=B)) <⋆> binddt ((ϕ (lam B) ○ f) ⦿ 1) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)ϕ (lam B -> lam B) (pure (abs (V:=B))) <⋆> ϕ (lam B) (binddt (f ⦿ 1) t) = pure (abs (V:=B)) <⋆> binddt ((ϕ (lam B) ○ f) ⦿ 1) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)pure (abs (V:=B)) <⋆> ϕ (lam B) (binddt (f ⦿ 1) t) = pure (abs (V:=B)) <⋆> binddt ((ϕ (lam B) ○ f) ⦿ 1) treflexivity.G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t: lam A
IHt: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t) = binddt (ϕ (lam B) ○ f) t
f: nat * A -> G1 (lam B)pure (abs (V:=B)) <⋆> binddt (ϕ (lam B) ○ f ⦿ 1) t = pure (abs (V:=B)) <⋆> binddt ((ϕ (lam B) ○ f) ⦿ 1) tG1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)ϕ (lam B) (binddt f (app t1 t2)) = binddt (ϕ (lam B) ○ f) (app t1 t2)G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)ϕ (lam B) (pure (app (V:=B)) <⋆> binddt f t1 <⋆> binddt f t2) = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)ϕ (lam B -> lam B) (pure (app (V:=B)) <⋆> binddt f t1) <⋆> ϕ (lam B) (binddt f t2) = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)ϕ (lam B -> lam B -> lam B) (pure (app (V:=B))) <⋆> ϕ (lam B) (binddt f t1) <⋆> ϕ (lam B) (binddt f t2) = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)pure (app (V:=B)) <⋆> ϕ (lam B) (binddt f t1) <⋆> ϕ (lam B) (binddt f t2) = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> ϕ (lam B) (binddt f t2) = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2reflexivity. Qed. #[export] Instance Map_Lam: Map lam := DerivedOperations.Map_Binddt nat lam lam. #[export] Instance Mapd_Lam: Mapd nat lam := DerivedOperations.Mapd_Binddt nat lam lam. #[export] Instance Traverse_Lam: Traverse lam := DerivedOperations.Traverse_Binddt nat lam lam. #[export] Instance Mapdt_Lam: Mapdt nat lam := DerivedOperations.Mapdt_Binddt nat lam lam. #[export] Instance Bind_Lam: Bind lam lam := DerivedOperations.Bind_Binddt nat lam lam. #[export] Instance Bindd_Lam: Bindd nat lam lam := DerivedOperations.Bindd_Binddt nat lam lam. #[export] Instance Bindt_Lam: Bindt lam lam := DerivedOperations.Bindt_Binddt nat lam lam. #[export] Instance ToSubset_Lam: ToSubset lam := ToSubset_Traverse. #[export] Instance ToBatch_Lam: ToBatch lam := DerivedOperations.ToBatch_Traverse. Import Notations. Implicit Types (s t u v: lam nat) (x y: nat) (σ τ: nat -> lam nat) (ρ: nat -> nat). Generalizable Variables s t u v x y σ τ ρ. Create HintDb churchrosser. Declare Custom Entry lambda. (* Import DB.DB.Notations. *) (* Tealeaves notations *) Import DB.AutosubstShim.Notations. (* Autosubst-like notations *) Module Notations. Notation "{| e |}" := e (e custom lambda at level 99). Notation "t1 t2" := (app t1 t2) (in custom lambda at level 1, left associativity). Notation "\, t" := (abs t) (in custom lambda at level 90, t custom lambda at level 99, left associativity). Notation "( x )" := x (in custom lambda, x at level 99). Notation "x" := x (in custom lambda at level 0, x constr at level 0). End Notations. Import Notations. (* One step of beta reduction *) Inductive step: lam nat -> lam nat -> Prop := | step_beta: forall tbody targ, step (app (abs tbody) targ) (subst (targ .: ret) tbody) | step_app_l: forall u1 u2 t, step u1 u2 -> step (app u1 t) (app u2 t) | step_app_r: forall u t1 t2, step t1 t2 -> step (app u t1) (app u t2) | step_lam: forall u1 u2, step u1 u2 -> step (abs u1) (abs u2). Notation "s → t" := (step s t) (at level 50). #[export] Hint Constructors step: churchrosser. Definition steps: relation (lam nat) := clos_refl_trans _ step.G1, G2: Type -> Type
H: Map G1
H0: Mult G1
H1: Pure G1
H2: Map G2
H3: Mult G2
H4: Pure G2
ϕ: forall A : Type, G1 A -> G2 A
morph: ApplicativeMorphism G1 G2 ϕ
A, B: Type
t1, t2: lam A
IHt1: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t1) = binddt (ϕ (lam B) ○ f) t1
IHt2: forall f : nat * A -> G1 (lam B), ϕ (lam B) (binddt f t2) = binddt (ϕ (lam B) ○ f) t2
f: nat * A -> G1 (lam B)pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2 = pure (app (V:=B)) <⋆> binddt (ϕ (lam B) ○ f) t1 <⋆> binddt (ϕ (lam B) ○ f) t2Reflexive stepsReflexive stepsapply rt_refl. Qed.forall x : lam nat, steps x xTransitive stepsTransitive stepsapply rt_trans. Qed. #[export] Hint Constructors clos_refl_trans: churchrosser. Notation "t1 →* t2" := (steps t1 t2) (at level 50).forall x y z : lam nat, steps x y -> steps y z -> steps x zforall s1 s2 t, s1 →* s2 -> {|s1 t|} →* {|s2 t|}forall s1 s2 t, s1 →* s2 -> {|s1 t|} →* {|s2 t|}s1, s2, t: lam nat
H: s1 →* s2{|s1 t|} →* {|s2 t|}t, x, y: lam nat
H: x → y{|x t|} →* {|y t|}t, x: lam nat{|x t|} →* {|x t|}t, x, y, z: lam nat
H: clos_refl_trans (lam nat) step x y
H0: clos_refl_trans (lam nat) step y z
IHclos_refl_trans1: {|x t|} →* {|y t|}
IHclos_refl_trans2: {|y t|} →* {|z t|}{|x t|} →* {|z t|}t, x, y: lam nat
H: x → y{|x t|} →* {|y t|}t, x, y: lam nat
H: x → y{|x t|} → {|y t|}assumption.t, x, y: lam nat
H: x → yx → yapply rt_refl.t, x: lam nat{|x t|} →* {|x t|}eapply rt_trans; eassumption. Qed.t, x, y, z: lam nat
H: clos_refl_trans (lam nat) step x y
H0: clos_refl_trans (lam nat) step y z
IHclos_refl_trans1: {|x t|} →* {|y t|}
IHclos_refl_trans2: {|y t|} →* {|z t|}{|x t|} →* {|z t|}forall s t1 t2, t1 →* t2 -> {|s t1|} →* {|s t2|}induction 1; unfold steps; eauto with churchrosser. Qed.forall s t1 t2, t1 →* t2 -> {|s t1|} →* {|s t2|}forall t1 t2, t1 →* t2 -> {|\, t1|} →* {|\, t2|}induction 1; unfold steps; eauto with churchrosser. Qed. #[export] Hint Resolve steps_app_r steps_lam steps_app_l: churchrosser. Section rel_properties. Context (R1 R2: relation (lam nat)). Definition GDiamond := forall t t1 t2, R1 t t1 -> R1 t t2 -> exists t3, R2 t1 t3 /\ R2 t2 t3. Definition Diamond := forall t t1 t2, R1 t t1 -> R1 t t2 -> exists t3, R1 t1 t3 /\ R1 t2 t3. End rel_properties. Definition local_confluence: Prop := GDiamond step steps. Definition confluence: Prop := Diamond steps. #[export] Hint Unfold confluence local_confluence Diamond GDiamond: core. Reserved Notation "t1 ⇒ t2" (at level 50). Inductive par: lam nat -> lam nat -> Prop := | par_refl : `(tvar x ⇒ tvar x) | par_app : `(s1 ⇒ s2 -> t1 ⇒ t2 -> {| s1 t1 |} ⇒ {| s2 t2 |}) | par_abs : `(s1 ⇒ s2 -> {|\, s1|} ⇒ {|\, s2|}) | par_beta : `(s1 ⇒ s2 -> t1 ⇒ t2 -> {| (\, s1) t1 |} ⇒ subst (t2 .: ret) s2) where "t1 ⇒ t2" := (par t1 t2).forall t1 t2, t1 →* t2 -> {|\, t1|} →* {|\, t2|}Reflexive parReflexive parinduction t; auto using par. Qed. Definition pars: relation (lam nat) := clos_refl_trans _ par.t: lam natt ⇒ tReflexive parsReflexive parsapply rt_refl. Qed.forall x : lam nat, pars x xTransitive parsTransitive parsapply rt_trans. Qed. Notation "t1 ⇒* t2" := (pars t1 t2) (at level 50). #[export] Hint Constructors par: churchrosser.forall x y z : lam nat, pars x y -> pars y z -> pars x z
forall t1 t2, t1 → t2 -> t1 ⇒ t2forall t1 t2, t1 → t2 -> t1 ⇒ t2t1, t2: lam nat
Hstep: t1 → t2t1 ⇒ t2tbody, targ: lam nat{|(\, tbody) targ|} ⇒ tbody.[targ/]u1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2{|u1 t|} ⇒ {|u2 t|}u, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2{|u t1|} ⇒ {|u t2|}u1, u2: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2{|\, u1|} ⇒ {|\, u2|}tbody, targ: lam nat{|(\, tbody) targ|} ⇒ tbody.[targ/]tbody, targ: lam nattbody ⇒ tbodytbody, targ: lam nattarg ⇒ targreflexivity.tbody, targ: lam nattbody ⇒ tbodyreflexivity.tbody, targ: lam nattarg ⇒ targu1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2{|u1 t|} ⇒ {|u2 t|}u1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2u1 ⇒ u2u1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2t ⇒ tassumption.u1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2u1 ⇒ u2reflexivity.u1, u2, t: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2t ⇒ tu, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2{|u t1|} ⇒ {|u t2|}u, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2u ⇒ uu, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2t1 ⇒ t2reflexivity.u, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2u ⇒ uassumption.u, t1, t2: lam nat
Hstep: t1 → t2
IHHstep: t1 ⇒ t2t1 ⇒ t2u1, u2: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2{|\, u1|} ⇒ {|\, u2|}assumption. Qed.u1, u2: lam nat
Hstep: u1 → u2
IHHstep: u1 ⇒ u2u1 ⇒ u2forall t1 t2, t1 ⇒ t2 -> t1 →* t2forall t1 t2, t1 ⇒ t2 -> t1 →* t2t1, t2: lam nat
Hstep: t1 ⇒ t2t1 →* t2x: nattvar x →* tvar xs1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t1|} →* {|s2 t2|}s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: s1 →* s2{|\, s1|} →* {|\, s2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t1|} →* s2.[t2/]reflexivity.x: nattvar x →* tvar xs1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t1|} →* {|s2 t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t1|} →* {|s1 t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t2|} →* {|s2 t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t1|} →* {|s1 t2|}assumption.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2t1 →* t2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|s1 t2|} →* {|s2 t2|}assumption.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2s1 →* s2s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: s1 →* s2{|\, s1|} →* {|\, s2|}assumption.s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: s1 →* s2s1 →* s2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t1|} →* s2.[t2/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t1|} →* {|(\, s1) t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t2|} →* s2.[t2/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t1|} →* {|(\, s1) t2|}assumption.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2t1 →* t2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t2|} →* s2.[t2/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t2|} →* {|(\, s2) t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s2) t2|} →* s2.[t2/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s1) t2|} →* {|(\, s2) t2|}s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|\, s1|} →* {|\, s2|}assumption.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2s1 →* s2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s2) t2|} →* s2.[t2/]apply step_beta. Qed.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: s1 →* s2
IHHstep2: t1 →* t2{|(\, s2) t2|} → s2.[t2/]forall t1 t2, t1 ⇒* t2 -> t1 →* t2forall t1 t2, t1 ⇒* t2 -> t1 →* t2x, y: lam nat
H: x ⇒ yx →* yx: lam natx →* xx, y, z: lam nat
H: clos_refl_trans (lam nat) par x y
H0: clos_refl_trans (lam nat) par y z
IHclos_refl_trans1: x →* y
IHclos_refl_trans2: y →* zx →* zx: lam natx →* xx, y, z: lam nat
H: clos_refl_trans (lam nat) par x y
H0: clos_refl_trans (lam nat) par y z
IHclos_refl_trans1: x →* y
IHclos_refl_trans2: y →* zx →* zetransitivity; eauto. Qed.x, y, z: lam nat
H: clos_refl_trans (lam nat) par x y
H0: clos_refl_trans (lam nat) par y z
IHclos_refl_trans1: x →* y
IHclos_refl_trans2: y →* zx →* zforall t1 t2, t1 →* t2 -> t1 ⇒* t2forall t1 t2, t1 →* t2 -> t1 ⇒* t2t1, t2: lam nat
Hstep: t1 →* t2t1 ⇒* t2x, y: lam nat
H: x → yx ⇒* yx: lam natx ⇒* xx, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* zx ⇒* zx, y: lam nat
H: x → yx ⇒* ynow apply step_in_par.x, y: lam nat
H: x → yx ⇒ yreflexivity.x: lam natx ⇒* xx, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* zx ⇒* zx, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* zx ⇒* ?yx, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* z?y ⇒* zeassumption.x, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* zx ⇒* ?yassumption. Qed.x, y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: x ⇒* y
IHHstep2: y ⇒* zy ⇒* zforall t1 t2, t1 → t2 -> t1 ⇒ t2induction 1; now constructor. Qed. #[export] Hint Resolve step_in_par: churchrosser.forall t1 t2, t1 → t2 -> t1 ⇒ t2forall t1 t2, t1 ⇒ t2 -> t1 →* t2forall t1 t2, t1 ⇒ t2 -> t1 →* t2x: nattvar x →* tvar xs1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|s1 t1|} →* {|s2 t2|}s1, s2: lam nat
H: s1 ⇒ s2
IHpar: s1 →* s2{|\, s1|} →* {|\, s2|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|(\, s1) t1|} →* s2.[t2/]reflexivity.x: nattvar x →* tvar xetransitivity...s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|s1 t1|} →* {|s2 t2|}idtac...s1, s2: lam nat
H: s1 ⇒ s2
IHpar: s1 →* s2{|\, s1|} →* {|\, s2|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|(\, s1) t1|} →* s2.[t2/]s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|(\, s2) t1|} →* s2.[t2/]s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2{|(\, s2) t2|} →* s2.[t2/]etransitivity... Qed.s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s1 →* s2
IHpar2: t1 →* t2clos_refl_trans (lam nat) step {|(\, s2) t2|} s2.[t2/]forall t1 t2, t1 →* t2 -> t1 ⇒* t2induction 1; unfold pars; eauto with churchrosser. Qed.forall t1 t2, t1 →* t2 -> t1 ⇒* t2forall t1 t2, t1 ⇒* t2 -> t1 →* t2forall t1 t2, t1 ⇒* t2 -> t1 →* t2x, y: lam nat
H: x ⇒ yclos_refl_trans (lam nat) step x yunfold pars... Qed. Notation "σ1 ▷ σ2" := (forall x, σ1 x ⇒ σ2 x) (at level 50). Tactic Notation "asimpl" := simplify_db_like_autosubst.x, y: lam nat
H: x ⇒ yx ⇒* yforall s t, s ⇒ t -> forall σ, s.[σ] ⇒ t.[σ]forall s t, s ⇒ t -> forall σ, s.[σ] ⇒ t.[σ]s, t: lam nat
Hstep: s ⇒ tforall σ, s.[σ] ⇒ t.[σ]x: nat
σ: nat -> lam nat(tvar x).[σ] ⇒ (tvar x).[σ]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|s1 t1|}.[σ] ⇒ {|s2 t2|}.[σ]s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ, s1.[σ] ⇒ s2.[σ]
σ: nat -> lam nat{|\, s1|}.[σ] ⇒ {|\, s2|}.[σ]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|(\, s1) t1|}.[σ] ⇒ s2.[t2/].[σ]x: nat
σ: nat -> lam nat(tvar x).[σ] ⇒ (tvar x).[σ]reflexivity.x: nat
σ: nat -> lam natσ x ⇒ σ xasimpl...s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|s1 t1|}.[σ] ⇒ {|s2 t2|}.[σ]asimpl...s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ, s1.[σ] ⇒ s2.[σ]
σ: nat -> lam nat{|\, s1|}.[σ] ⇒ {|\, s2|}.[σ]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|(\, s1) t1|}.[σ] ⇒ s2.[t2/].[σ]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|(\, (s1.[ret 0 .: σ >>> subst ((+1) >>> ret)])) (t1.[σ])|} ⇒ s2.[t2.[σ] .: σ]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nat{|(\, (s1.[ret 0 .: σ >>> subst ((+1) >>> ret)])) (t1.[σ])|} ⇒ s2.[up__sub σ].[t2.[σ]/]asimpl... Qed.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ, s1.[σ] ⇒ s2.[σ]
IHHstep2: forall σ, t1.[σ] ⇒ t2.[σ]
σ: nat -> lam nats1.[ret 0 .: σ >>> subst ((+1) >>> ret)] ⇒ s2.[up__sub σ]forall t1 t2 ρ, t1 ⇒ t2 -> rename ρ t1 ⇒ rename ρ t2forall t1 t2 ρ, t1 ⇒ t2 -> rename ρ t1 ⇒ rename ρ t2t1, t2: lam nat
ρ: nat -> nat
H: t1 ⇒ t2rename ρ t1 ⇒ rename ρ t2t1, t2: lam nat
ρ: nat -> nat
H: t1 ⇒ t2t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]t1, t2: lam nat
H: t1 ⇒ t2forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]x: nat
ρ: nat -> nat(tvar x).[ρ >>> ret] ⇒ (tvar x).[ρ >>> ret]s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
IHpar2: forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]
ρ: nat -> nat{|s1 t1|}.[ρ >>> ret] ⇒ {|s2 t2|}.[ρ >>> ret]s1, s2: lam nat
H: s1 ⇒ s2
IHpar: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
ρ: nat -> nat{|\, s1|}.[ρ >>> ret] ⇒ {|\, s2|}.[ρ >>> ret]s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
IHpar2: forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]
ρ: nat -> nat{|(\, s1) t1|}.[ρ >>> ret] ⇒ s2.[t2/].[ρ >>> ret]reflexivity.x: nat
ρ: nat -> nat(tvar x).[ρ >>> ret] ⇒ (tvar x).[ρ >>> ret]asimpl...s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
IHpar2: forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]
ρ: nat -> nat{|s1 t1|}.[ρ >>> ret] ⇒ {|s2 t2|}.[ρ >>> ret]s1, s2: lam nat
H: s1 ⇒ s2
IHpar: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
ρ: nat -> nat{|\, s1|}.[ρ >>> ret] ⇒ {|\, s2|}.[ρ >>> ret]eauto with churchrosser.s1, s2: lam nat
H: s1 ⇒ s2
IHpar: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
ρ: nat -> nat{|\, (s1.[0 .: ρ >>> (+1) >>> ret])|} ⇒ {|\, (s2.[0 .: ρ >>> (+1) >>> ret])|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
IHpar2: forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]
ρ: nat -> nat{|(\, s1) t1|}.[ρ >>> ret] ⇒ s2.[t2/].[ρ >>> ret]asimpl... Qed.s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: forall ρ, s1.[ρ >>> ret] ⇒ s2.[ρ >>> ret]
IHpar2: forall ρ, t1.[ρ >>> ret] ⇒ t2.[ρ >>> ret]
ρ: nat -> nat(rename (up__ren ρ) s1 ⇒ rename (up__ren ρ) s2 -> rename ρ t1 ⇒ rename ρ t2 -> {|(\, (rename (up__ren ρ) s1)) (rename ρ t1)|} ⇒ (rename (up__ren ρ) s2).[ rename ρ t2/]) -> {|(\, s1) t1|}.[ρ >>> ret] ⇒ s2.[t2/].[ρ >>> ret]forall σ1 σ2, σ1 ▷ σ2 -> up__sub σ1 ▷ up__sub σ2forall σ1 σ2, σ1 ▷ σ2 -> up__sub σ1 ▷ up__sub σ2σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: natup__sub σ1 x ⇒ up__sub σ2 xσ1, σ2: nat -> lam nat
H: σ1 ▷ σ2up__sub σ1 0 ⇒ up__sub σ2 0σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xup__sub σ1 (S x) ⇒ up__sub σ2 (S x)reflexivity.σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2up__sub σ1 0 ⇒ up__sub σ2 0σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xup__sub σ1 (S x) ⇒ up__sub σ2 (S x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 x
H0: rename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)up__sub σ1 (S x) ⇒ up__sub σ2 (S x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xrename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 x
H0: rename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)(ret 0 .: σ1 >>> subst ((+1) >>> ret)) (S x) ⇒ (ret 0 .: σ2 >>> subst ((+1) >>> ret)) (S x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xrename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 x
H0: (σ1 x).[(+1) >>> ret] ⇒ (σ2 x).[(+1) >>> ret](ret 0 .: σ1 >>> subst ((+1) >>> ret)) (S x) ⇒ (ret 0 .: σ2 >>> subst ((+1) >>> ret)) (S x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xrename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 x
H0: (σ1 x).[(+1) >>> ret] ⇒ (σ2 x).[(+1) >>> ret](σ1 >>> subst ((+1) >>> ret)) x ⇒ (σ2 >>> subst ((+1) >>> ret)) xσ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xrename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xrename (+1) (σ1 x) ⇒ rename (+1) (σ2 x)apply H. Qed.σ1, σ2: nat -> lam nat
H: σ1 ▷ σ2
x: nat
IHx: up__sub σ1 x ⇒ up__sub σ2 xσ1 x ⇒ σ2 xs, t: lam nat
σ1, σ2: nat -> lam nats ⇒ t -> σ1 ▷ σ2 -> s.[σ1] ⇒ t.[σ2]s, t: lam nat
σ1, σ2: nat -> lam nats ⇒ t -> σ1 ▷ σ2 -> s.[σ1] ⇒ t.[σ2]s, t: lam nat
σ1, σ2: nat -> lam nat
Hstep: s ⇒ tσ1 ▷ σ2 -> s.[σ1] ⇒ t.[σ2]s, t: lam nat
σ2: nat -> lam nat
Hstep: s ⇒ tforall σ1, σ1 ▷ σ2 -> s.[σ1] ⇒ t.[σ2]s, t: lam nat
Hstep: s ⇒ tforall σ2 σ1, σ1 ▷ σ2 -> s.[σ1] ⇒ t.[σ2]x: nat
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2(tvar x).[σ1] ⇒ (tvar x).[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|s1 t1|}.[σ1] ⇒ {|s2 t2|}.[σ2]s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|\, s1|}.[σ1] ⇒ {|\, s2|}.[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|(\, s1) t1|}.[σ1] ⇒ s2.[t2/].[σ2]asimpl...x: nat
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2(tvar x).[σ1] ⇒ (tvar x).[σ2]asimpl...s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|s1 t1|}.[σ1] ⇒ {|s2 t2|}.[σ2]s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|\, s1|}.[σ1] ⇒ {|\, s2|}.[σ2]s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|\, (s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)])|} ⇒ {|\, (s2.[ret 0 .: σ2 >>> subst ((+1) >>> ret)])|}s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)] ⇒ s2.[ret 0 .: σ2 >>> subst ((+1) >>> ret)]s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2(ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ (ret 0 .: σ2 >>> subst ((+1) >>> ret))s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2up__sub σ1 ▷ up__sub σ2 -> (ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ (ret 0 .: σ2 >>> subst ((+1) >>> ret))auto.s1, s2: lam nat
Hstep: s1 ⇒ s2
IHHstep: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2(ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ (ret 0 .: σ2 >>> subst ((+1) >>> ret)) -> (ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ (ret 0 .: σ2 >>> subst ((+1) >>> ret))s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|(\, s1) t1|}.[σ1] ⇒ s2.[t2/].[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|(\, (s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)])) (t1.[σ1])|} ⇒ s2.[t2.[σ2] .: σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|(\, (s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)])) (t1.[σ1])|} ⇒ s2.[up__sub σ2].[t2.[σ2]/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s2.[up__sub σ2].[t2.[σ2]/] = s2.[t2.[σ2] .: σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2{|(\, (s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)])) (t1.[σ1])|} ⇒ s2.[up__sub σ2].[t2.[σ2]/]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s1.[ret 0 .: σ1 >>> subst ((+1) >>> ret)] ⇒ s2.[up__sub σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2t1.[σ1] ⇒ t2.[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2(ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ up__sub σ2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2t1.[σ1] ⇒ t2.[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2up__sub σ1 ▷ up__sub σ2 -> (ret 0 .: σ1 >>> subst ((+1) >>> ret)) ▷ up__sub σ2s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2t1.[σ1] ⇒ t2.[σ2]auto.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2t1.[σ1] ⇒ t2.[σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s2.[up__sub σ2].[t2.[σ2]/] = s2.[t2.[σ2] .: σ2]s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s2.[up__sub σ2].[t2.[σ2]/] = s2.[t2.[σ2] .: σ2]reflexivity. } Qed.s1, s2, t1, t2: lam nat
Hstep1: s1 ⇒ s2
Hstep2: t1 ⇒ t2
IHHstep1: forall σ2 σ1, σ1 ▷ σ2 -> s1.[σ1] ⇒ s2.[σ2]
IHHstep2: forall σ2 σ1, σ1 ▷ σ2 -> t1.[σ1] ⇒ t2.[σ2]
σ2, σ1: nat -> lam nat
Hsub: σ1 ▷ σ2s2.[(t2.[σ2] .: ret) 0 .: σ2] = s2.[t2.[σ2] .: σ2]
Fixpoint normalize (t: lam nat): lam nat := match t with | tvar x => tvar x | abs s => abs (normalize s) | app (abs t1) t2 => (normalize t1).[normalize t2/] | app t1 t2 => app (normalize t1) (normalize t2) end.forall t1 t2, t1 ⇒ t2 -> t2 ⇒ normalize t1forall t1 t2, t1 ⇒ t2 -> t2 ⇒ normalize t1t1, t2: lam nat
H: t1 ⇒ t2t2 ⇒ normalize t1t1: lam natforall t2, t1 ⇒ t2 -> t2 ⇒ normalize t1x: nattvar x ⇒ normalize (tvar x)s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ normalize {|s1 t1|}s1, s2: lam nat
H: s1 ⇒ s2
IHpar: s2 ⇒ normalize s1{|\, s2|} ⇒ normalize {|\, s1|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1s2.[t2/] ⇒ normalize {|(\, s1) t1|}reflexivity.x: nattvar x ⇒ normalize (tvar x)s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ normalize {|s1 t1|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ match s1 with | {|\, t2|} => (normalize t2).[normalize t1/] | _ => {|(normalize s1) (normalize t1)|} endn: nat
s2, t1, t2: lam nat
H: tvar n ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize (tvar n)
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ {|(normalize (tvar n)) (normalize t1)|}s1, s2, t1, t2: lam nat
H: {|\, s1|} ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ (normalize s1).[normalize t1/]s1_1, s1_2, s2, t1, t2: lam nat
H: {|s1_1 s1_2|} ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize {|s1_1 s1_2|}
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ {|(normalize {|s1_1 s1_2|}) (normalize t1)|}auto using par_app.n: nat
s2, t1, t2: lam nat
H: tvar n ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize (tvar n)
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ {|(normalize (tvar n)) (normalize t1)|}s1, s2, t1, t2: lam nat
H: {|\, s1|} ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ (normalize s1).[normalize t1/]s1, s2, t1, t2: lam nat
H: {|\, s1|} ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1
s0, s3: lam nat
H2: s1 ⇒ s3
H1: s0 = s1
H3: {|\, s3|} = s2{|(\, s3) t2|} ⇒ (normalize s1).[normalize t1/]s1, t1, t2, s3: lam nat
H: {|\, s1|} ⇒ {|\, s3|}
H0: t1 ⇒ t2
IHpar1: {|\, s3|} ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1
H2: s1 ⇒ s3{|(\, s3) t2|} ⇒ (normalize s1).[normalize t1/]s1, t1, t2, s3: lam nat
H: {|\, s1|} ⇒ {|\, s3|}
H0: t1 ⇒ t2
IHpar1: {|\, s3|} ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1
H2: s1 ⇒ s3
s0, s2: lam nat
H4: s3 ⇒ normalize s1
H1: s0 = s3
H3: s2 = normalize s1{|(\, s3) t2|} ⇒ (normalize s1).[normalize t1/]auto using par_beta.s1, t1, t2, s3: lam nat
H: {|\, s1|} ⇒ {|\, s3|}
H0: t1 ⇒ t2
IHpar1: {|\, s3|} ⇒ normalize {|\, s1|}
IHpar2: t2 ⇒ normalize t1
H2: s1 ⇒ s3
H4: s3 ⇒ normalize s1{|(\, s3) t2|} ⇒ (normalize s1).[normalize t1/]auto using par_app.s1_1, s1_2, s2, t1, t2: lam nat
H: {|s1_1 s1_2|} ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize {|s1_1 s1_2|}
IHpar2: t2 ⇒ normalize t1{|s2 t2|} ⇒ {|(normalize {|s1_1 s1_2|}) (normalize t1)|}s1, s2: lam nat
H: s1 ⇒ s2
IHpar: s2 ⇒ normalize s1{|\, s2|} ⇒ normalize {|\, s1|}auto using par_abs.s1, s2: lam nat
H: s1 ⇒ s2
IHpar: s2 ⇒ normalize s1{|\, s2|} ⇒ {|\, (normalize s1)|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1s2.[t2/] ⇒ normalize {|(\, s1) t1|}s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1s2.[t2/] ⇒ (normalize s1).[normalize t1/]s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1s2 ⇒ normalize s1s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1(t2 .: ret) ▷ (normalize t1 .: ret)now intros [|?]. Qed.s1, s2, t1, t2: lam nat
H: s1 ⇒ s2
H0: t1 ⇒ t2
IHpar1: s2 ⇒ normalize s1
IHpar2: t2 ⇒ normalize t1(t2 .: ret) ▷ (normalize t1 .: ret)Diamond parDiamond parforall t t1 t2, t ⇒ t1 -> t ⇒ t2 -> exists t3, t1 ⇒ t3 /\ t2 ⇒ t3t, t1, t2: lam nat
H1: t ⇒ t1
H2: t ⇒ t2exists t3, t1 ⇒ t3 /\ t2 ⇒ t3intuition auto using par_triangle. Qed.t, t1, t2: lam nat
H1: t ⇒ t1
H2: t ⇒ t2t1 ⇒ normalize t /\ t2 ⇒ normalize tforall t t1 t2, t ⇒ t1 -> t ⇒* t2 -> exists t3, t1 ⇒* t3 /\ t2 ⇒ t3forall t t1 t2, t ⇒ t1 -> t ⇒* t2 -> exists t3, t1 ⇒* t3 /\ t2 ⇒ t3t, t1, t2: lam nat
H1: t ⇒ t1
Hstar: t ⇒* t2exists t3, t1 ⇒* t3 /\ t2 ⇒ t3t, t2: lam nat
Hstar: t ⇒* t2forall t1, t ⇒ t1 -> exists t3, t1 ⇒* t3 /\ t2 ⇒ t3t, y: lam nat
H: t ⇒ y
t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ y ⇒ t3t, t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ t ⇒ t3t, y, z: lam nat
Hstar1: clos_refl_trans (lam nat) par t y
Hstar2: clos_refl_trans (lam nat) par y z
IHHstar1: forall t1, t ⇒ t1 -> exists t3, t1 ⇒* t3 /\ y ⇒ t3
IHHstar2: forall t1, y ⇒ t1 -> exists t3, t1 ⇒* t3 /\ z ⇒ t3
t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ z ⇒ t3t, y: lam nat
H: t ⇒ y
t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ y ⇒ t3t, t2: lam nat
H: t ⇒ t2
t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ t2 ⇒ t3exists t3; unfold pars; split...t, t2: lam nat
H: t ⇒ t2
t1: lam nat
H1: t ⇒ t1
t3: lam nat
H0: t1 ⇒ t3
H2: t2 ⇒ t3exists t3, t1 ⇒* t3 /\ t2 ⇒ t3t, t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ t ⇒ t3split; [reflexivity| auto].t, t1: lam nat
H1: t ⇒ t1t1 ⇒* t1 /\ t ⇒ t1t, y, z: lam nat
Hstar1: clos_refl_trans (lam nat) par t y
Hstar2: clos_refl_trans (lam nat) par y z
IHHstar1: forall t1, t ⇒ t1 -> exists t3, t1 ⇒* t3 /\ y ⇒ t3
IHHstar2: forall t1, y ⇒ t1 -> exists t3, t1 ⇒* t3 /\ z ⇒ t3
t1: lam nat
H1: t ⇒ t1exists t3, t1 ⇒* t3 /\ z ⇒ t3t, y, z: lam nat
Hstar1: clos_refl_trans (lam nat) par t y
Hstar2: clos_refl_trans (lam nat) par y z
IHHstar2: forall t1, y ⇒ t1 -> exists t3, t1 ⇒* t3 /\ z ⇒ t3
t1: lam nat
H1: t ⇒ t1
t3: lam nat
H: t1 ⇒* t3
H0: y ⇒ t3exists t3, t1 ⇒* t3 /\ z ⇒ t3t, y, z: lam nat
Hstar1: clos_refl_trans (lam nat) par t y
Hstar2: clos_refl_trans (lam nat) par y z
t1: lam nat
H1: t ⇒ t1
t3: lam nat
H: t1 ⇒* t3
H0: y ⇒ t3
t4: lam nat
H2: t3 ⇒* t4
H3: z ⇒ t4exists t3, t1 ⇒* t3 /\ z ⇒ t3split; [etransitivity; eauto| assumption]. Qed.t, y, z: lam nat
Hstar1: clos_refl_trans (lam nat) par t y
Hstar2: clos_refl_trans (lam nat) par y z
t1: lam nat
H1: t ⇒ t1
t3: lam nat
H: t1 ⇒* t3
H0: y ⇒ t3
t4: lam nat
H2: t3 ⇒* t4
H3: z ⇒ t4t1 ⇒* t4 /\ z ⇒ t4Diamond parsDiamond parsforall t t1 t2, t ⇒* t1 -> t ⇒* t2 -> exists t3, t1 ⇒* t3 /\ t2 ⇒* t3t, t1, t2: lam nat
Ht1: t ⇒* t1
Ht2: t ⇒* t2exists t3, t1 ⇒* t3 /\ t2 ⇒* t3t, t1: lam nat
Ht1: t ⇒* t1forall t2, t ⇒* t2 -> exists t3, t1 ⇒* t3 /\ t2 ⇒* t3x, y: lam nat
H: x ⇒ y
t2: lam nat
Ht2: x ⇒* t2exists t3, y ⇒* t3 /\ t2 ⇒* t3x, t2: lam nat
Ht2: x ⇒* t2exists t3, x ⇒* t3 /\ t2 ⇒* t3x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2exists t3, z ⇒* t3 /\ t2 ⇒* t3x, y: lam nat
H: x ⇒ y
t2: lam nat
Ht2: x ⇒* t2exists t3, y ⇒* t3 /\ t2 ⇒* t3t, y: lam nat
H: t ⇒ y
t2: lam nat
Ht2: t ⇒* t2exists t3, y ⇒* t3 /\ t2 ⇒* t3t, t1: lam nat
H: t ⇒ t1
t2: lam nat
Ht2: t ⇒* t2exists t3, t1 ⇒* t3 /\ t2 ⇒* t3t, t1: lam nat
H: t ⇒ t1
t2: lam nat
Ht2: t ⇒* t2
t3: lam nat
H0: t1 ⇒* t3
H1: t2 ⇒ t3exists t3, t1 ⇒* t3 /\ t2 ⇒* t3t, t1: lam nat
H: t ⇒ t1
t2: lam nat
Ht2: t ⇒* t2
t3: lam nat
H0: t1 ⇒* t3
H1: t2 ⇒ t3t1 ⇒* t3 /\ t2 ⇒* t3split; auto with churchrosser.t, t1: lam nat
H: t ⇒ t1
t2: lam nat
Ht2: clos_refl_trans (lam nat) par t t2
t3: lam nat
H0: clos_refl_trans (lam nat) par t1 t3
H1: t2 ⇒ t3clos_refl_trans (lam nat) par t1 t3 /\ clos_refl_trans (lam nat) par t2 t3x, t2: lam nat
Ht2: x ⇒* t2exists t3, x ⇒* t3 /\ t2 ⇒* t3x, t2: lam nat
Ht2: x ⇒* t2x ⇒* t2 /\ t2 ⇒* t2split; auto with churchrosser.x, t2: lam nat
Ht2: clos_refl_trans (lam nat) par x t2clos_refl_trans (lam nat) par x t2 /\ clos_refl_trans (lam nat) par t2 t2x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2exists t3, z ⇒* t3 /\ t2 ⇒* t3x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3exists t3, z ⇒* t3 /\ t2 ⇒* t3x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3
t4: lam nat
H1: z ⇒* t4
H2: t3 ⇒* t4exists t3, z ⇒* t3 /\ t2 ⇒* t3x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3
t4: lam nat
H1: z ⇒* t4
H2: t3 ⇒* t4z ⇒* t4 /\ t2 ⇒* t4x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3
t4: lam nat
H1: z ⇒* t4
H2: t3 ⇒* t4z ⇒* t4x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3
t4: lam nat
H1: z ⇒* t4
H2: t3 ⇒* t4t2 ⇒* t4etransitivity; eauto. Qed.x, y, z: lam nat
Ht1_1: clos_refl_trans (lam nat) par x y
Ht1_2: clos_refl_trans (lam nat) par y z
IHHt1_1: forall t2, x ⇒* t2 -> exists t3, y ⇒* t3 /\ t2 ⇒* t3
IHHt1_2: forall t2, y ⇒* t2 -> exists t3, z ⇒* t3 /\ t2 ⇒* t3
t2: lam nat
Ht2: x ⇒* t2
t3: lam nat
H: y ⇒* t3
H0: t2 ⇒* t3
t4: lam nat
H1: z ⇒* t4
H2: t3 ⇒* t4t2 ⇒* t4
confluenceconfluenceDiamond stepsforall t t1 t2, t →* t1 -> t →* t2 -> exists t3, t1 →* t3 /\ t2 →* t3t, t1, t2: lam nat
H: t →* t1
H0: t →* t2exists t3, t1 →* t3 /\ t2 →* t3t, t1, t2: lam nat
H: t →* t1
H0: t →* t2
H1: t ⇒* t1exists t3, t1 →* t3 /\ t2 →* t3t, t1, t2: lam nat
H: t →* t1
H0: t →* t2
H1: t ⇒* t1
H2: t ⇒* t2exists t3, t1 →* t3 /\ t2 →* t3exists t3; split; now apply pars_in_steps. Qed.t, t1, t2: lam nat
H: t →* t1
H0: t →* t2
H1: t ⇒* t1
H2: t ⇒* t2
t3: lam nat
H3: t1 ⇒* t3
H4: t2 ⇒* t3exists t3, t1 →* t3 /\ t2 →* t3
There are a couple ways to define the notion of \(\beta\)-equivalence (a/k/a \(\beta\)-conversion or \(\beta\)-congruence). Just as steps was defined as the reflexive transitive closure of step, beta_equiv can be defined as the reflexive symmetric transitive closure of step, i.e. the smallest equivalence relation that contains step.
As with steps, the first thing we do after defining beta_equiv is prove that it is indeed reflexive, symmetric, and transitive, enabling the use of the correspondingly named tactics. We also give this relation a custom notation and add its constructors to our hint database.
Definition beta_equiv: relation (lam nat) := clos_refl_sym_trans _ step.Reflexive beta_equivReflexive beta_equivapply rst_refl. Qed.forall x : lam nat, beta_equiv x xSymmetric beta_equivSymmetric beta_equivapply rst_sym. Qed.forall x y : lam nat, beta_equiv x y -> beta_equiv y xTransitive beta_equivTransitive beta_equivapply rst_trans. Qed. Notation "s ∼ t" := (beta_equiv s t) (at level 50). #[export] Hint Constructors clos_refl_sym_trans: churchrosser.forall x y z : lam nat, beta_equiv x y -> beta_equiv y z -> beta_equiv x z
Beta equivalence is also called a congruence relation, meaning an equivalence relation that is respected by a set of operations, in this case the constructors of (lam nat). By "respected by the constructors of (lam nat)" I mean exactly the following three properties, much like ones we gave earlier for steps.
forall s1 s2 t, s1 ∼ s2 -> {|s1 t|} ∼ {|s2 t|}induction 1; unfold beta_equiv; eauto with churchrosser. Qed.forall s1 s2 t, s1 ∼ s2 -> {|s1 t|} ∼ {|s2 t|}forall t1 t2 s, t1 ∼ t2 -> {|s t1|} ∼ {|s t2|}induction 1; unfold beta_equiv; eauto with churchrosser. Qed.forall t1 t2 s, t1 ∼ t2 -> {|s t1|} ∼ {|s t2|}forall t1 t2, t1 ∼ t2 -> {|\, t1|} ∼ {|\, t2|}induction 1; unfold beta_equiv; eauto with churchrosser. Qed. #[export] Hint Resolve beta_equiv_app_r beta_equiv_lam beta_equiv_app_l: churchrosser.forall t1 t2, t1 ∼ t2 -> {|\, t1|} ∼ {|\, t2|}
Instead of defining \(\beta\)-equivalence as the equivalence closure of step, another route is to define the relation inductively from a set of equational axioms, as shown below with beta_equiv_I.
Reserved Notation "s ≃ t" (at level 50). Inductive beta_equiv_I: lam nat -> lam nat -> Prop := | equ_refl: `(s ≃ s) | equ_sym : `(s ≃ t -> t ≃ s) | equ_trans: `(s ≃ t -> t ≃ u -> s ≃ u) | equ_beta: `({|(\, s) t|} ≃ s.[t/]) | equ_app_l: `(s1 ≃ s2 -> {|s1 t|} ≃ {|s2 t|}) | equ_app_r: `(t1 ≃ t2 -> {|s t1|} ≃ {|s t2|}) | equ_lam: `(s1 ≃ s2 -> {|\, s1|} ≃ {|\, s2|}) where "s ≃ t" := (beta_equiv_I s t). #[export] Hint Constructors beta_equiv_I: churchrosser.
If you're following along in Barendregt, this definition of \(\beta\)-congruence matches Barendregt's definition of the equational theory λ (Definition 2.1.4, pg. 23). In some sense this style of definition is simpler to think about (and to generalize to other calculi) because it does not require introducing an auxiliary relation like step. This could be beneficial in situations where we know which terms we want to be equal, but it is not clear how to describe this equality in terms of reduction steps.
It is easy to show that our two definitions of beta conversion coincide.
forall s t, s ∼ t <-> s ≃ tforall s t, s ∼ t <-> s ≃ ts, t: lam nats ∼ t <-> s ≃ ts, t: lam nats ∼ t -> s ≃ ts, t: lam nats ≃ t -> s ∼ ts, t: lam nats ∼ t -> s ≃ tx, y: lam nat
H: x → yx ≃ yx, y, z: lam nat
H: clos_refl_sym_trans (lam nat) step x y
H0: clos_refl_sym_trans (lam nat) step y z
IHclos_refl_sym_trans1: x ≃ y
IHclos_refl_sym_trans2: y ≃ zx ≃ zinduction H...x, y: lam nat
H: x → yx ≃ yeauto with churchrosser.x, y, z: lam nat
H: clos_refl_sym_trans (lam nat) step x y
H0: clos_refl_sym_trans (lam nat) step y z
IHclos_refl_sym_trans1: x ≃ y
IHclos_refl_sym_trans2: y ≃ zx ≃ zs, t: lam nats ≃ t -> s ∼ ts: lam nats ∼ ss, t: lam nat
H: s ≃ t
IHbeta_equiv_I: s ∼ tt ∼ ss, t, u: lam nat
H: s ≃ t
H0: t ≃ u
IHbeta_equiv_I1: s ∼ t
IHbeta_equiv_I2: t ∼ us ∼ us, t: lam nat{|(\, s) t|} ∼ s.[t/]reflexivity.s: lam nats ∼ ssymmetry...s, t: lam nat
H: s ≃ t
IHbeta_equiv_I: s ∼ tt ∼ setransitivity; eassumption.s, t, u: lam nat
H: s ≃ t
H0: t ≃ u
IHbeta_equiv_I1: s ∼ t
IHbeta_equiv_I2: t ∼ us ∼ uunfold beta_equiv... Qed.s, t: lam nat{|(\, s) t|} ∼ s.[t/]
Confluence is a pleasing technical property with a few useful corollaries. First, if we want to know whether two terms are beta-equivalent, by confluence it suffices to check whether the terms can be reduced to a common term. This is important because, at face value, deciding equivalence sounds much harder. Second, it implies that if a given lambda term t reduces to some irreducible term s, this property unique defines s. This is important because beta-reduction is non-deterministic, and the prior statement implies any reduction sequence that discovers a normal form for t must find the same normal form. In the context of typed lambda calculi that enjoy strong normalization (a separate topic), this fact implies it is decidable whether two terms are \(beta\)-equivalent. In particular, this a crucial theoretical fact underlying how Coq itself decides whether two terms are defintionally equal, a key aspect of Coq and theorem proving in general.
Definition have_common_reduct: lam nat -> lam nat -> Prop := fun s t => exists u, s →* u /\ t →* u.Transitive have_common_reductTransitive have_common_reductforall x y z : lam nat, have_common_reduct x y -> have_common_reduct y z -> have_common_reduct x zs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tvhave_common_reduct s vs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
cut: have_common_reduct st tvhave_common_reduct s vs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tvhave_common_reduct st tvs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
cut: have_common_reduct st tvhave_common_reduct s vs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
cut: exists u, st →* u /\ tv →* uexists u, s →* u /\ v →* us, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
u: lam nat
H3: st →* u
H4: tv →* uexists u, s →* u /\ v →* usplit; etransitivity; eassumption.s, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
u: lam nat
H3: st →* u
H4: tv →* us →* u /\ v →* us, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tvhave_common_reduct st tvs, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tvexists u, st →* u /\ tv →* us, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
u: lam nat
H3: st →* u
H4: tv →* uexists u, st →* u /\ tv →* utauto. Qed.s, t, v, st: lam nat
H: s →* st
H0: t →* st
tv: lam nat
H1: t →* tv
H2: v →* tv
u: lam nat
H3: st →* u
H4: tv →* ust →* u /\ tv →* u
The following specification theorem for \(\beta\)-conversion states that two terms are \(\beta\)-equivalent exactly when they share a common reduct. The non-obvious case of this proof is exactly showing the transitivity of the have_common_reduct relation. This case is unfolded below to show the proof state before invoking transitivity.
forall s t, have_common_reduct s t <-> s ∼ tforall s t, have_common_reduct s t <-> s ∼ ts, t: lam nathave_common_reduct s t <-> s ∼ ts, t: lam nathave_common_reduct s t -> s ∼ ts, t: lam nats ∼ t -> have_common_reduct s ts, t, st: lam nat
H: s →* st
H0: t →* sts ∼ ts, t: lam nats ∼ t -> have_common_reduct s ts, t, st: lam nat
H: s →* st
H0: t →* sts ∼ ts, t, st: lam nat
H: s →* st
H0: t →* sts ∼ sts, t, st: lam nat
H: s →* st
H0: t →* stst ∼ ts, t, st: lam nat
H: s →* st
H0: t →* sts ∼ sts, t, st: lam nat
H: s →* st
H0: t →* stclos_refl_trans (lam nat) step s stassumption.s, t, st: lam nat
H: s →* st
H0: t →* sts →* sts, t, st: lam nat
H: s →* st
H0: t →* stst ∼ ts, t, st: lam nat
H: s →* st
H0: t →* stt ∼ sts, t, st: lam nat
H: s →* st
H0: t →* stt ∼ sts, t, st: lam nat
H: s →* st
H0: t →* stclos_refl_trans (lam nat) step t stassumption.s, t, st: lam nat
H: s →* st
H0: t →* stt →* sts, t: lam nats ∼ t -> have_common_reduct s ts, t: lam nat
H: s ∼ thave_common_reduct s tx, y: lam nat
H: x → yhave_common_reduct x yx: lam nathave_common_reduct x xx, y: lam nat
H: clos_refl_sym_trans (lam nat) step x y
IHclos_refl_sym_trans: have_common_reduct x yhave_common_reduct y xx, y, z: lam nat
H: clos_refl_sym_trans (lam nat) step x y
H0: clos_refl_sym_trans (lam nat) step y z
IHclos_refl_sym_trans1: have_common_reduct x y
IHclos_refl_sym_trans2: have_common_reduct y zhave_common_reduct x zx, y: lam nat
H: x → yhave_common_reduct x yunfold steps...x, y: lam nat
H: x → yx →* y /\ y →* yx: lam nathave_common_reduct x xunfold steps...x: lam natx →* x /\ x →* xx, y: lam nat
H: clos_refl_sym_trans (lam nat) step x y
IHclos_refl_sym_trans: have_common_reduct x yhave_common_reduct y xx, y: lam nat
H: clos_refl_sym_trans (lam nat) step x y
z: lam nat
H0: x →* z
H1: y →* zhave_common_reduct y xtauto.x, y: lam nat
H: clos_refl_sym_trans (lam nat) step x y
z: lam nat
H0: x →* z
H1: y →* zy →* z /\ x →* zetransitivity; eassumption. Qed.x, y, z: lam nat
H: clos_refl_sym_trans (lam nat) step x y
H0: clos_refl_sym_trans (lam nat) step y z
IHclos_refl_sym_trans1: have_common_reduct x y
IHclos_refl_sym_trans2: have_common_reduct y zhave_common_reduct x z
Definition beta_normal (t: lam nat): Prop := not (exists s, t → s). Definition has_normal_form (t s: lam nat): Prop := t →* s /\ beta_normal s.forall t s, beta_normal t -> t →* s -> t = sforall t s, beta_normal t -> t →* s -> t = st, s: lam nat
Hnorm: beta_normal t
Hstep: t →* st = sx: lam nat
Hnorm: beta_normal x
y: lam nat
H: x → yx = yx: lam nat
Hnorm: beta_normal xx = xx: lam nat
Hnorm: beta_normal x
y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: beta_normal x -> x = y
IHHstep2: beta_normal y -> y = zx = zx: lam nat
Hnorm: beta_normal x
y: lam nat
H: x → yx = yeauto.x: lam nat
Hnorm: beta_normal x
y: lam nat
H: x → yexists s, x → sreflexivity.x: lam nat
Hnorm: beta_normal xx = xx: lam nat
Hnorm: beta_normal x
y, z: lam nat
Hstep1: clos_refl_trans (lam nat) step x y
Hstep2: clos_refl_trans (lam nat) step y z
IHHstep1: beta_normal x -> x = y
IHHstep2: beta_normal y -> y = zx = zx: lam nat
Hnorm: beta_normal x
y, z: lam nat
Hstep1: x →* y
Hstep2: y →* z
IHHstep1: beta_normal x -> x = y
IHHstep2: beta_normal y -> y = zx = zx: lam nat
Hnorm: beta_normal x
y, z: lam nat
Hstep1: x →* y
Hstep2: y →* z
IHHstep1: x = y
IHHstep2: beta_normal y -> y = zx = zy: lam nat
Hnorm: beta_normal y
z: lam nat
Hstep1: y →* y
Hstep2: y →* z
IHHstep2: beta_normal y -> y = zy = zapply Hnorm. Qed.y: lam nat
Hnorm: beta_normal y
z: lam nat
Hstep1: y →* y
Hstep2: y →* z
IHHstep2: beta_normal y -> y = zbeta_normal yforall t s1 s2, has_normal_form t s1 -> has_normal_form t s2 -> s1 = s2forall t s1 s2, has_normal_form t s1 -> has_normal_form t s2 -> s1 = s2forall t s1 s2, t →* s1 /\ beta_normal s1 -> t →* s2 /\ beta_normal s2 -> s1 = s2t, s1, s2: lam nat
t_step_s1: t →* s1
s1_normal: beta_normal s1
t_step_s2: t →* s2
s2_normal: beta_normal s2s1 = s2t, s1, s2: lam nat
t_step_s1: t →* s1
s1_normal: beta_normal s1
t_step_s2: t →* s2
s2_normal: beta_normal s2
s: lam nat
s1_step_s: s1 →* s
s2_step_s: s2 →* ss1 = s2t, s1, s2: lam nat
t_step_s1: t →* s1
s1_normal: beta_normal s1
t_step_s2: t →* s2
s2_normal: beta_normal s2
s: lam nat
s1_step_s: s1 →* s
s2_step_s: s2 →* s
H: s1 = ss1 = s2congruence. Qed.t, s1, s2: lam nat
t_step_s1: t →* s1
s1_normal: beta_normal s1
t_step_s2: t →* s2
s2_normal: beta_normal s2
s: lam nat
s1_step_s: s1 →* s
s2_step_s: s2 →* s
H: s1 = s
H0: s2 = ss1 = s2forall t s, t ∼ s -> beta_normal s -> t →* sforall t s, t ∼ s -> beta_normal s -> t →* st, s: lam nat
Heq: t ∼ s
normal_s: beta_normal st →* st, s: lam nat
Hcr: have_common_reduct t s
normal_s: beta_normal st →* st, s, u: lam nat
Htu: t →* u
Hsu: s →* u
normal_s: beta_normal st →* st, s, u: lam nat
Htu: t →* u
Hsu: s →* u
normal_s: beta_normal s
H: s = ut →* sassumption. Qed.t, u: lam nat
Htu: t →* u
normal_s: beta_normal u
Hsu: u →* ut →* uforall t t' s, t →* t' -> has_normal_form t s -> has_normal_form t' sforall t t' s, t →* t' -> has_normal_form t s -> has_normal_form t' sforall t t' s, t →* t' -> t →* s /\ beta_normal s -> t' →* s /\ beta_normal st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' →* s /\ beta_normal st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' →* st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal sbeta_normal st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' →* st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' ∼ st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal sbeta_normal st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' ∼ st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' ∼ tt, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st ∼ st, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st' ∼ tt, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st ∼ t'assumption.t, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st →* t't, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st ∼ sassumption.t, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal st →* sassumption.t, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal sbeta_normal sassumption. Qed.t, t', s: lam nat
t_step_t': t →* t'
t_step_s: t →* s
s_normal: beta_normal sbeta_normal sforall t t', t →* t' -> t ∼ t'forall t t', t →* t' -> t ∼ t't, t': lam nat
H: t →* t't ∼ t'assumption. Qed.t, t': lam nat
H: t →* t'clos_refl_trans (lam nat) step t t'forall t t' s, t ∼ t' -> has_normal_form t s -> has_normal_form t' sforall t t' s, t ∼ t' -> has_normal_form t s -> has_normal_form t' sforall t t' s, t ∼ t' -> t →* s /\ beta_normal s -> t' →* s /\ beta_normal st, t', s: lam nat
t_equiv_t': t ∼ t'
t_step_s: t →* s
normal_s: beta_normal st' →* s /\ beta_normal st, t', s: lam nat
t_equiv_t': t ∼ t'
t_step_s: t →* s
normal_s: beta_normal st' →* st, t', s: lam nat
t_equiv_t': t ∼ t'
t_step_s: t →* s
normal_s: beta_normal st' ∼ setransitivity; [symmetry|]; eauto. Qed.t, t', s: lam nat
t_equiv_t': t ∼ t'
t_step_s: t ∼ s
normal_s: beta_normal st' ∼ s