Definition: C_TYPEco
C_TYPEco() ==
  corec(X.lbl:Atom × if lbl =a "Void" then Unit
                     if lbl =a "Int" then Unit
                     if lbl =a "Struct" then (Atom × X) List
                     if lbl =a "Array" then length:ℕ × X
                     if lbl =a "Pointer" then X
                     else Void
                     fi )

Lemma: C_TYPEco_wf
C_TYPEco() ∈ Type

Lemma: C_TYPEco-ext
C_TYPEco() ≡ lbl:Atom × if lbl =a "Void" then Unit
                        if lbl =a "Int" then Unit
                        if lbl =a "Struct" then (Atom × C_TYPEco()) List
                        if lbl =a "Array" then length:ℕ × C_TYPEco()
                        if lbl =a "Pointer" then C_TYPEco()
                        else Void
                        fi 

Definition: C_TYPEco_size
C_TYPEco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Void" then 0
                   if lbl =a "Int" then 0
                   if lbl =a "Struct" then + Σ(size (snd(x[i])) i < ||x||)
                   if lbl =a "Array" then (size (snd(x)))
                   if lbl =a "Pointer" then (size x)
                   else 0
                   fi )) 
  p

Lemma: C_TYPEco_size_wf
[p:C_TYPEco()]. (C_TYPEco_size(p) ∈ partial(ℕ))

Definition: C_TYPE
C_TYPE() ==  {p:C_TYPEco()| (C_TYPEco_size(p))↓

Lemma: C_TYPE_wf
C_TYPE() ∈ Type

Definition: C_TYPE_size
C_TYPE_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Void" then 0
                   if lbl =a "Int" then 0
                   if lbl =a "Struct" then + Σ(size (snd(x[i])) i < ||x||)
                   if lbl =a "Array" then (size (snd(x)))
                   if lbl =a "Pointer" then (size x)
                   else 0
                   fi )) 
  p

Lemma: C_TYPE_size_wf
[p:C_TYPE()]. (C_TYPE_size(p) ∈ ℕ)

Lemma: C_TYPE-ext
C_TYPE() ≡ lbl:Atom × if lbl =a "Void" then Unit
                      if lbl =a "Int" then Unit
                      if lbl =a "Struct" then (Atom × C_TYPE()) List
                      if lbl =a "Array" then length:ℕ × C_TYPE()
                      if lbl =a "Pointer" then C_TYPE()
                      else Void
                      fi 

Definition: C_Void
C_Void() ==  <"Void", ⋅>

Lemma: C_Void_wf
C_Void() ∈ C_TYPE()

Definition: C_Int
C_Int() ==  <"Int", ⋅>

Lemma: C_Int_wf
C_Int() ∈ C_TYPE()

Definition: C_Struct
C_Struct(fields) ==  <"Struct", fields>

Lemma: C_Struct_wf
[fields:(Atom × C_TYPE()) List]. (C_Struct(fields) ∈ C_TYPE())

Definition: C_Array
C_Array(length;elems) ==  <"Array", length, elems>

Lemma: C_Array_wf
[length:ℕ]. ∀[elems:C_TYPE()].  (C_Array(length;elems) ∈ C_TYPE())

Definition: C_Pointer
C_Pointer(to) ==  <"Pointer", to>

Lemma: C_Pointer_wf
[to:C_TYPE()]. (C_Pointer(to) ∈ C_TYPE())

Definition: C_Void?
C_Void?(v) ==  fst(v) =a "Void"

Lemma: C_Void?_wf
[v:C_TYPE()]. (C_Void?(v) ∈ 𝔹)

Definition: C_Int?
C_Int?(v) ==  fst(v) =a "Int"

Lemma: C_Int?_wf
[v:C_TYPE()]. (C_Int?(v) ∈ 𝔹)

Definition: C_Struct?
C_Struct?(v) ==  fst(v) =a "Struct"

Lemma: C_Struct?_wf
[v:C_TYPE()]. (C_Struct?(v) ∈ 𝔹)

Definition: C_Struct-fields
C_Struct-fields(v) ==  snd(v)

Lemma: C_Struct-fields_wf
[v:C_TYPE()]. C_Struct-fields(v) ∈ (Atom × C_TYPE()) List supposing ↑C_Struct?(v)

Definition: C_Array?
C_Array?(v) ==  fst(v) =a "Array"

Lemma: C_Array?_wf
[v:C_TYPE()]. (C_Array?(v) ∈ 𝔹)

Definition: C_Array-length
C_Array-length(v) ==  fst(snd(v))

Lemma: C_Array-length_wf
[v:C_TYPE()]. C_Array-length(v) ∈ ℕ supposing ↑C_Array?(v)

Definition: C_Array-elems
C_Array-elems(v) ==  snd(snd(v))

Lemma: C_Array-elems_wf
[v:C_TYPE()]. C_Array-elems(v) ∈ C_TYPE() supposing ↑C_Array?(v)

Definition: C_Pointer?
C_Pointer?(v) ==  fst(v) =a "Pointer"

Lemma: C_Pointer?_wf
[v:C_TYPE()]. (C_Pointer?(v) ∈ 𝔹)

Definition: C_Pointer-to
C_Pointer-to(v) ==  snd(v)

Lemma: C_Pointer-to_wf
[v:C_TYPE()]. C_Pointer-to(v) ∈ C_TYPE() supposing ↑C_Pointer?(v)

Lemma: C_TYPE-induction
[P:C_TYPE() ⟶ ℙ]
  (P[C_Void()]
   P[C_Int()]
   (∀fields:(Atom × C_TYPE()) List. ((∀u∈fields.let u1,u2 in P[u2])  P[C_Struct(fields)]))
   (∀length:ℕ. ∀elems:C_TYPE().  (P[elems]  P[C_Array(length;elems)]))
   (∀to:C_TYPE(). (P[to]  P[C_Pointer(to)]))
   {∀v:C_TYPE(). P[v]})

Lemma: C_TYPE-definition
[A:Type]. ∀[R:A ⟶ C_TYPE() ⟶ ℙ].
  ({x:A| R[x;C_Void()]} 
   {x:A| R[x;C_Int()]} 
   (∀fields:(Atom × C_TYPE()) List. ((∀u∈fields.let u1,u2 in {x:A| R[x;u2]}  {x:A| R[x;C_Struct(fields)]} ))
   (∀length:ℕ. ∀elems:C_TYPE().  ({x:A| R[x;elems]}   {x:A| R[x;C_Array(length;elems)]} ))
   (∀to:C_TYPE(). ({x:A| R[x;to]}   {x:A| R[x;C_Pointer(to)]} ))
   {∀v:C_TYPE(). {x:A| R[x;v]} })

Definition: C_TYPE_ind
C_TYPE_ind(v
Void=>Void
Int=>Int
Struct(fields)=>rec1.Struct[fields; rec1]
Array(length,elems)=>rec2.Array[length; elems; rec2]
Pointer(to)=>rec3.Pointer[to; rec3]) ==
  fix((λC_TYPE_ind,v. let lbl,v1 
                      in if lbl="Void" then Void
                         if lbl="Int" then Int
                         if lbl="Struct" then Struct[v1; λi.let v2,v3 v1[i] in C_TYPE_ind v3]
                         if lbl="Array" then let length,v2 v1 in Array[length; v2; C_TYPE_ind v2]
                         if lbl="Pointer" then Pointer[v1; C_TYPE_ind v1]
                         else Ax
                         fi )) 
  v

Lemma: C_TYPE_ind_wf
[A:Type]. ∀[R:A ⟶ C_TYPE() ⟶ ℙ]. ∀[v:C_TYPE()]. ∀[Void:{x:A| R[x;C_Void()]} ]. ∀[Int:{x:A| R[x;C_Int()]} ].
[Struct:fields:((Atom × C_TYPE()) List)
         ⟶ (∀u∈fields.let u1,u2 
                       in {x:A| R[x;u2]} )
         ⟶ {x:A| R[x;C_Struct(fields)]} ]. ∀[Array:length:ℕ
                                                   ⟶ elems:C_TYPE()
                                                   ⟶ {x:A| R[x;elems]} 
                                                   ⟶ {x:A| R[x;C_Array(length;elems)]} ].
[Pointer:to:C_TYPE() ⟶ {x:A| R[x;to]}  ⟶ {x:A| R[x;C_Pointer(to)]} ].
  (C_TYPE_ind(v
   Void=>Void
   Int=>Int
   Struct(fields)=>rec1.Struct[fields;rec1]
   Array(length,elems)=>rec2.Array[length;elems;rec2]
   Pointer(to)=>rec3.Pointer[to;rec3]) ∈ {x:A| R[x;v]} )

Lemma: C_TYPE_ind_wf_simple
[A:Type]. ∀[v:C_TYPE()]. ∀[Void,Int:A].
[Struct:fields:((Atom × C_TYPE()) List) ⟶ (∀u∈fields.let u1,u2 in A) ⟶ A]. ∀[Array:length:ℕ
                                                                                          ⟶ elems:C_TYPE()
                                                                                          ⟶ A
                                                                                          ⟶ A]. ∀[Pointer:to:C_TYPE()
                                                                                                           ⟶ A
                                                                                                           ⟶ A].
  (C_TYPE_ind(v
   Void=>Void
   Int=>Int
   Struct(fields)=>rec1.Struct[fields;rec1]
   Array(length,elems)=>rec2.Array[length;elems;rec2]
   Pointer(to)=>rec3.Pointer[to;rec3]) ∈ A)

Lemma: C_TYPE_subtype_base
C_TYPE() ⊆Base

Definition: C_TYPE_eq_fun
C_TYPE_eq_fun(a) ==
  C_TYPE_ind(a
  Void=>λb.C_Void?(b)
  Int=>λb.C_Int?(b)
  Struct(fields)=>rec.λb.(C_Struct?(b)
                         ∧b (||fields|| =z ||C_Struct-fields(b)||)
                         ∧b (∀i∈upto(||fields||).fst(fields[i]) =a fst(C_Struct-fields(b)[i])
                               ∧b (rec (snd(C_Struct-fields(b)[i]))))_b)
  Array(length,elems)=>rec.λb.(C_Array?(b) ∧b (length =z C_Array-length(b)) ∧b (rec C_Array-elems(b)))
  Pointer(to)=>rec.λb.(C_Pointer?(b) ∧b (rec C_Pointer-to(b))))

Lemma: C_TYPE_eq_fun_wf
[a:C_TYPE()]. (C_TYPE_eq_fun(a) ∈ C_TYPE() ⟶ 𝔹)

Definition: C_TYPE_eq
C_TYPE_eq(a;b) ==  C_TYPE_eq_fun(a) b

Lemma: C_TYPE_eq_wf
[a,b:C_TYPE()].  (C_TYPE_eq(a;b) ∈ 𝔹)

Lemma: assert-C_TYPE_eq
[a,b:C_TYPE()].  uiff(↑C_TYPE_eq(a;b);a b ∈ C_TYPE())

Lemma: C_TYPE-induction2
[P:C_TYPE() ⟶ ℙ]
  (P[C_Void()]
   P[C_Int()]
   (∀fields:(Atom × C_TYPE()) List. ((∀i:ℕ||fields||. P[snd(fields[i])])  P[C_Struct(fields)]))
   (∀length:ℕ. ∀elems:C_TYPE().  (P[elems]  P[C_Array(length;elems)]))
   (∀to:C_TYPE(). (P[to]  P[C_Pointer(to)]))
   {∀x:C_TYPE(). P[x]})

Lemma: C_TYPE-induction3
[P:C_TYPE() ⟶ ℙ]
  (P[C_Void()]
   P[C_Int()]
   (∀fields:(Atom × C_TYPE()) List. ((∀ct∈map(λp.(snd(p));fields).P[ct])  P[C_Struct(fields)]))
   (∀length:ℕ. ∀elems:C_TYPE().  (P[elems]  P[C_Array(length;elems)]))
   (∀to:C_TYPE(). (P[to]  P[C_Pointer(to)]))
   {∀x:C_TYPE(). P[x]})

Lemma: C_TYPE-valueall-type
valueall-type(C_TYPE())

Definition: C_TYPE-rank
C_TYPE-rank(ctyp) ==
  C_TYPE_ind(ctyp
  Void=>0
  Int=>0
  Struct(fields)=>recL.Σ(recL j < ||fields||)
  Array(length,elems)=>recA.recA 1
  Pointer(to)=>recP.recP 1)

Lemma: C_TYPE-rank_wf
[ctyp:C_TYPE()]. (C_TYPE-rank(ctyp) ∈ ℕ)

Definition: C_LOCATION
C_LOCATION() ==  ℤ

Lemma: C_LOCATION_wf
C_LOCATION() ∈ Type

Definition: C_LVALUEco
C_LVALUEco() ==
  corec(X.lbl:Atom × if lbl =a "Ground" then C_LOCATION()
                     if lbl =a "Index" then lval:X × ℤ
                     if lbl =a "Scomp" then lval:X × Atom
                     else Void
                     fi )

Lemma: C_LVALUEco_wf
C_LVALUEco() ∈ Type

Lemma: C_LVALUEco-ext
C_LVALUEco() ≡ lbl:Atom × if lbl =a "Ground" then C_LOCATION()
                          if lbl =a "Index" then lval:C_LVALUEco() × ℤ
                          if lbl =a "Scomp" then lval:C_LVALUEco() × Atom
                          else Void
                          fi 

Definition: C_LVALUEco_size
C_LVALUEco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Ground" then 0
                   if lbl =a "Index" then let lval,z in (size lval)
                   if lbl =a "Scomp" then let lval,z in (size lval)
                   else 0
                   fi )) 
  p

Lemma: C_LVALUEco_size_wf
[p:C_LVALUEco()]. (C_LVALUEco_size(p) ∈ partial(ℕ))

Definition: C_LVALUE
C_LVALUE() ==  {p:C_LVALUEco()| (C_LVALUEco_size(p))↓

Lemma: C_LVALUE_wf
C_LVALUE() ∈ Type

Definition: C_LVALUE_size
C_LVALUE_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Ground" then 0
                   if lbl =a "Index" then let lval,z in (size lval)
                   if lbl =a "Scomp" then let lval,z in (size lval)
                   else 0
                   fi )) 
  p

Lemma: C_LVALUE_size_wf
[p:C_LVALUE()]. (C_LVALUE_size(p) ∈ ℕ)

Lemma: C_LVALUE-ext
C_LVALUE() ≡ lbl:Atom × if lbl =a "Ground" then C_LOCATION()
                        if lbl =a "Index" then lval:C_LVALUE() × ℤ
                        if lbl =a "Scomp" then lval:C_LVALUE() × Atom
                        else Void
                        fi 

Definition: LV_Ground
LV_Ground(loc) ==  <"Ground", loc>

Lemma: LV_Ground_wf
[loc:C_LOCATION()]. (LV_Ground(loc) ∈ C_LVALUE())

Definition: LV_Index
LV_Index(lval;idx) ==  <"Index", lval, idx>

Lemma: LV_Index_wf
[lval:C_LVALUE()]. ∀[idx:ℤ].  (LV_Index(lval;idx) ∈ C_LVALUE())

Definition: LV_Scomp
LV_Scomp(lval;comp) ==  <"Scomp", lval, comp>

Lemma: LV_Scomp_wf
[lval:C_LVALUE()]. ∀[comp:Atom].  (LV_Scomp(lval;comp) ∈ C_LVALUE())

Definition: LV_Ground?
LV_Ground?(v) ==  fst(v) =a "Ground"

Lemma: LV_Ground?_wf
[v:C_LVALUE()]. (LV_Ground?(v) ∈ 𝔹)

Definition: LV_Ground-loc
LV_Ground-loc(v) ==  snd(v)

Lemma: LV_Ground-loc_wf
[v:C_LVALUE()]. LV_Ground-loc(v) ∈ C_LOCATION() supposing ↑LV_Ground?(v)

Definition: LV_Index?
LV_Index?(v) ==  fst(v) =a "Index"

Lemma: LV_Index?_wf
[v:C_LVALUE()]. (LV_Index?(v) ∈ 𝔹)

Definition: LV_Index-lval
LV_Index-lval(v) ==  fst(snd(v))

Lemma: LV_Index-lval_wf
[v:C_LVALUE()]. LV_Index-lval(v) ∈ C_LVALUE() supposing ↑LV_Index?(v)

Definition: LV_Index-idx
LV_Index-idx(v) ==  snd(snd(v))

Lemma: LV_Index-idx_wf
[v:C_LVALUE()]. LV_Index-idx(v) ∈ ℤ supposing ↑LV_Index?(v)

Definition: LV_Scomp?
LV_Scomp?(v) ==  fst(v) =a "Scomp"

Lemma: LV_Scomp?_wf
[v:C_LVALUE()]. (LV_Scomp?(v) ∈ 𝔹)

Definition: LV_Scomp-lval
LV_Scomp-lval(v) ==  fst(snd(v))

Lemma: LV_Scomp-lval_wf
[v:C_LVALUE()]. LV_Scomp-lval(v) ∈ C_LVALUE() supposing ↑LV_Scomp?(v)

Definition: LV_Scomp-comp
LV_Scomp-comp(v) ==  snd(snd(v))

Lemma: LV_Scomp-comp_wf
[v:C_LVALUE()]. LV_Scomp-comp(v) ∈ Atom supposing ↑LV_Scomp?(v)

Lemma: C_LVALUE-induction
[P:C_LVALUE() ⟶ ℙ]
  ((∀loc:C_LOCATION(). P[LV_Ground(loc)])
   (∀lval:C_LVALUE(). ∀idx:ℤ.  (P[lval]  P[LV_Index(lval;idx)]))
   (∀lval:C_LVALUE(). ∀comp:Atom.  (P[lval]  P[LV_Scomp(lval;comp)]))
   {∀v:C_LVALUE(). P[v]})

Lemma: C_LVALUE-definition
[A:Type]. ∀[R:A ⟶ C_LVALUE() ⟶ ℙ].
  ((∀loc:C_LOCATION(). {x:A| R[x;LV_Ground(loc)]} )
   (∀lval:C_LVALUE(). ∀idx:ℤ.  ({x:A| R[x;lval]}   {x:A| R[x;LV_Index(lval;idx)]} ))
   (∀lval:C_LVALUE(). ∀comp:Atom.  ({x:A| R[x;lval]}   {x:A| R[x;LV_Scomp(lval;comp)]} ))
   {∀v:C_LVALUE(). {x:A| R[x;v]} })

Definition: C_LVALUE_ind
C_LVALUE_ind(v;
             LV_Ground(loc) Ground[loc];
             LV_Index(lval,idx) rec1.Index[lval; idx; rec1];
             LV_Scomp(lval,comp) rec2.Scomp[lval; comp; rec2])  ==
  fix((λC_LVALUE_ind,v. let lbl,v1 
                        in if lbl="Ground" then Ground[v1]
                           if lbl="Index" then let lval,v2 v1 in Index[lval; v2; C_LVALUE_ind lval]
                           if lbl="Scomp" then let lval,v2 v1 in Scomp[lval; v2; C_LVALUE_ind lval]
                           else Ax
                           fi )) 
  v

Lemma: C_LVALUE_ind_wf
[A:Type]. ∀[R:A ⟶ C_LVALUE() ⟶ ℙ]. ∀[v:C_LVALUE()]. ∀[Ground:loc:C_LOCATION() ⟶ {x:A| R[x;LV_Ground(loc)]} ].
[Index:lval:C_LVALUE() ⟶ idx:ℤ ⟶ {x:A| R[x;lval]}  ⟶ {x:A| R[x;LV_Index(lval;idx)]} ].
[Scomp:lval:C_LVALUE() ⟶ comp:Atom ⟶ {x:A| R[x;lval]}  ⟶ {x:A| R[x;LV_Scomp(lval;comp)]} ].
  (C_LVALUE_ind(v;
                LV_Ground(loc) Ground[loc];
                LV_Index(lval,idx) rec1.Index[lval;idx;rec1];
                LV_Scomp(lval,comp) rec2.Scomp[lval;comp;rec2])  ∈ {x:A| R[x;v]} )

Lemma: C_LVALUE_ind_wf_simple
[A:Type]. ∀[v:C_LVALUE()]. ∀[Ground:loc:C_LOCATION() ⟶ A]. ∀[Index:lval:C_LVALUE() ⟶ idx:ℤ ⟶ A ⟶ A].
[Scomp:lval:C_LVALUE() ⟶ comp:Atom ⟶ A ⟶ A].
  (C_LVALUE_ind(v;
                LV_Ground(loc) Ground[loc];
                LV_Index(lval,idx) rec1.Index[lval;idx;rec1];
                LV_Scomp(lval,comp) rec2.Scomp[lval;comp;rec2])  ∈ A)

Definition: C_field_of
C_field_of(a;ctyp) ==  a ∈b map(λx.(fst(x));C_Struct-fields(ctyp))

Lemma: C_field_of_wf
[a:Atom]. ∀[ctyp:{t:C_TYPE()| ↑C_Struct?(t)} ].  (C_field_of(a;ctyp) ∈ 𝔹)

Definition: C_type_of_field
C_type_of_field(a;ctyp) ==  outl(apply-alist(AtomDeq;C_Struct-fields(ctyp);a))

Lemma: C_type_of_field_wf
[ctyp:{t:C_TYPE()| ↑C_Struct?(t)} ]. ∀[a:{c:Atom| ↑C_field_of(c;ctyp)} ].  (C_type_of_field(a;ctyp) ∈ C_TYPE())

Definition: C_TYPE_env
C_TYPE_env() ==  C_LOCATION() ⟶ (C_TYPE()?)

Lemma: C_TYPE_env_wf
C_TYPE_env() ∈ Type

Definition: C_TYPE-of-LVALUE
C_TYPE-of-LVALUE(env;lval) ==
  case lval is  
  Ground(loc) => env loc  
  aval[idx] => let case of aval in if isl(r)
               then if C_Array?(outl(r))
                    then if 0 ≤idx ∧b idx <C_Array-length(outl(r)) then inl C_Array-elems(outl(r)) else inr ⋅  fi 
                    else inr ⋅ 
                    fi 
               else inr ⋅ 
               fi   
  sval.comp =>  let r2 case of sval in if isl(r2)
               then if C_Struct?(outl(r2)) then apply-alist(AtomDeq;C_Struct-fields(outl(r2));comp) else inr ⋅  fi 
               else inr ⋅ 
               fi )

Lemma: C_TYPE-of-LVALUE_wf
env:C_TYPE_env(). ∀lval:C_LVALUE().  (C_TYPE-of-LVALUE(env;lval) ∈ C_TYPE()?)

Definition: C_LVALUE-proper
C_LVALUE-proper(env;lval) ==  isl(C_TYPE-of-LVALUE(env;lval))

Lemma: C_LVALUE-proper_wf
env:C_TYPE_env(). ∀lval:C_LVALUE().  (C_LVALUE-proper(env;lval) ∈ 𝔹)

Lemma: C_LVALUE-proper-Ground
env:C_TYPE_env(). ∀lval:C_LVALUE().
  ((↑LV_Ground?(lval))  (↑C_LVALUE-proper(env;lval))  (↑isl(env LV_Ground-loc(lval))))

Lemma: C_LVALUE-proper-Index
env:C_TYPE_env(). ∀lval:C_LVALUE().
  ((↑LV_Index?(lval))
   (↑C_LVALUE-proper(env;lval))
   let lval' LV_Index-lval(lval) in
      let LV_Index-idx(lval) in
      let typ outl(C_TYPE-of-LVALUE(env;lval')) in
      (↑C_LVALUE-proper(env;lval')) ∧ (↑C_Array?(typ)) ∧ (0 ≤ i) ∧ i < C_Array-length(typ))

Lemma: C_LVALUE-proper-Indexed
env:C_TYPE_env(). ∀lval:C_LVALUE(). ∀i:ℤ.
  ((↑C_LVALUE-proper(env;LV_Index(lval;i)))  (↑C_Array?(outl(C_TYPE-of-LVALUE(env;lval)))))

Lemma: C_LVALUE-proper-Scomp
env:C_TYPE_env(). ∀lval:C_LVALUE().
  ((↑LV_Scomp?(lval))
   (↑C_LVALUE-proper(env;lval))
   let lval' LV_Scomp-lval(lval) in
      let LV_Scomp-comp(lval) in
      let typ outl(C_TYPE-of-LVALUE(env;lval')) in
      (↑C_LVALUE-proper(env;lval')) ∧ (↑C_Struct?(typ)) ∧ (↑C_field_of(a;typ)))

Lemma: C_LVALUE-proper-Scomped
env:C_TYPE_env(). ∀lval:C_LVALUE(). ∀a:Atom.
  ((↑C_LVALUE-proper(env;LV_Scomp(lval;a)))  (↑C_Struct?(outl(C_TYPE-of-LVALUE(env;lval)))))

Definition: C_DVALUEpco
C_DVALUEpco() ==
  corec(X.lbl:Atom × if lbl =a "Null" then Unit
                     if lbl =a "Int" then ℤ
                     if lbl =a "Pointer" then C_LVALUE()?
                     if lbl =a "Array" then lower:ℤ × upper:ℤ × ({lower..upper-} ⟶ X)
                     if lbl =a "Struct" then lbls:Atom List × ({a:Atom| (a ∈ lbls)}  ⟶ X)
                     else Void
                     fi )

Lemma: C_DVALUEpco_wf
C_DVALUEpco() ∈ Type

Lemma: C_DVALUEpco-ext
C_DVALUEpco() ≡ lbl:Atom × if lbl =a "Null" then Unit
                           if lbl =a "Int" then ℤ
                           if lbl =a "Pointer" then C_LVALUE()?
                           if lbl =a "Array" then lower:ℤ × upper:ℤ × ({lower..upper-} ⟶ C_DVALUEpco())
                           if lbl =a "Struct" then lbls:Atom List × ({a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEpco())
                           else Void
                           fi 

Definition: C_DVALUEpco_size
C_DVALUEpco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Null" then 0
                   if lbl =a "Int" then 0
                   if lbl =a "Pointer" then 0
                   if lbl =a "Array"
                     then 1
                          + Σ(size ((snd(snd(x))) ((fst(x)) i)) i < if fst(x) ≤fst(snd(x))
                            then (fst(snd(x))) fst(x)
                            else 0
                            fi )
                   if lbl =a "Struct" then + Σ(size ((snd(x)) fst(x)[a]) a < ||fst(x)||)
                   else 0
                   fi )) 
  p

Lemma: C_DVALUEpco_size_wf
[p:C_DVALUEpco()]. (C_DVALUEpco_size(p) ∈ partial(ℕ))

Definition: C_DVALUEp
C_DVALUEp() ==  {p:C_DVALUEpco()| (C_DVALUEpco_size(p))↓

Lemma: C_DVALUEp_wf
C_DVALUEp() ∈ Type

Definition: C_DVALUEp_size
C_DVALUEp_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Null" then 0
                   if lbl =a "Int" then 0
                   if lbl =a "Pointer" then 0
                   if lbl =a "Array"
                     then 1
                          + Σ(size ((snd(snd(x))) ((fst(x)) i)) i < if fst(x) ≤fst(snd(x))
                            then (fst(snd(x))) fst(x)
                            else 0
                            fi )
                   if lbl =a "Struct" then + Σ(size ((snd(x)) fst(x)[a]) a < ||fst(x)||)
                   else 0
                   fi )) 
  p

Lemma: C_DVALUEp_size_wf
[p:C_DVALUEp()]. (C_DVALUEp_size(p) ∈ ℕ)

Lemma: C_DVALUEp-ext
C_DVALUEp() ≡ lbl:Atom × if lbl =a "Null" then Unit
                         if lbl =a "Int" then ℤ
                         if lbl =a "Pointer" then C_LVALUE()?
                         if lbl =a "Array" then lower:ℤ × upper:ℤ × ({lower..upper-} ⟶ C_DVALUEp())
                         if lbl =a "Struct" then lbls:Atom List × ({a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp())
                         else Void
                         fi 

Definition: DVp_Null
DVp_Null(x) ==  <"Null", x>

Lemma: DVp_Null_wf
[x:Unit]. (DVp_Null(x) ∈ C_DVALUEp())

Definition: DVp_Int
DVp_Int(int) ==  <"Int", int>

Lemma: DVp_Int_wf
[int:ℤ]. (DVp_Int(int) ∈ C_DVALUEp())

Definition: DVp_Pointer
DVp_Pointer(ptr) ==  <"Pointer", ptr>

Lemma: DVp_Pointer_wf
[ptr:C_LVALUE()?]. (DVp_Pointer(ptr) ∈ C_DVALUEp())

Definition: DVp_Array
DVp_Array(lower;upper;arr) ==  <"Array", lower, upper, arr>

Lemma: DVp_Array_wf
[lower,upper:ℤ]. ∀[arr:{lower..upper-} ⟶ C_DVALUEp()].  (DVp_Array(lower;upper;arr) ∈ C_DVALUEp())

Definition: DVp_Struct
DVp_Struct(lbls;struct) ==  <"Struct", lbls, struct>

Lemma: DVp_Struct_wf
[lbls:Atom List]. ∀[struct:{a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp()].  (DVp_Struct(lbls;struct) ∈ C_DVALUEp())

Definition: DVp_Null?
DVp_Null?(v) ==  fst(v) =a "Null"

Lemma: DVp_Null?_wf
[v:C_DVALUEp()]. (DVp_Null?(v) ∈ 𝔹)

Definition: DVp_Null-x
DVp_Null-x(v) ==  snd(v)

Lemma: DVp_Null-x_wf
[v:C_DVALUEp()]. DVp_Null-x(v) ∈ Unit supposing ↑DVp_Null?(v)

Definition: DVp_Int?
DVp_Int?(v) ==  fst(v) =a "Int"

Lemma: DVp_Int?_wf
[v:C_DVALUEp()]. (DVp_Int?(v) ∈ 𝔹)

Definition: DVp_Int-int
DVp_Int-int(v) ==  snd(v)

Lemma: DVp_Int-int_wf
[v:C_DVALUEp()]. DVp_Int-int(v) ∈ ℤ supposing ↑DVp_Int?(v)

Definition: DVp_Pointer?
DVp_Pointer?(v) ==  fst(v) =a "Pointer"

Lemma: DVp_Pointer?_wf
[v:C_DVALUEp()]. (DVp_Pointer?(v) ∈ 𝔹)

Definition: DVp_Pointer-ptr
DVp_Pointer-ptr(v) ==  snd(v)

Lemma: DVp_Pointer-ptr_wf
[v:C_DVALUEp()]. DVp_Pointer-ptr(v) ∈ C_LVALUE()? supposing ↑DVp_Pointer?(v)

Definition: DVp_Array?
DVp_Array?(v) ==  fst(v) =a "Array"

Lemma: DVp_Array?_wf
[v:C_DVALUEp()]. (DVp_Array?(v) ∈ 𝔹)

Definition: DVp_Array-lower
DVp_Array-lower(v) ==  fst(snd(v))

Lemma: DVp_Array-lower_wf
[v:C_DVALUEp()]. DVp_Array-lower(v) ∈ ℤ supposing ↑DVp_Array?(v)

Definition: DVp_Array-upper
DVp_Array-upper(v) ==  fst(snd(snd(v)))

Lemma: DVp_Array-upper_wf
[v:C_DVALUEp()]. DVp_Array-upper(v) ∈ ℤ supposing ↑DVp_Array?(v)

Definition: DVp_Array-arr
DVp_Array-arr(v) ==  snd(snd(snd(v)))

Lemma: DVp_Array-arr_wf
[v:C_DVALUEp()]. DVp_Array-arr(v) ∈ {DVp_Array-lower(v)..DVp_Array-upper(v)-} ⟶ C_DVALUEp() supposing ↑DVp_Array?(v)

Definition: DVp_Struct?
DVp_Struct?(v) ==  fst(v) =a "Struct"

Lemma: DVp_Struct?_wf
[v:C_DVALUEp()]. (DVp_Struct?(v) ∈ 𝔹)

Definition: DVp_Struct-lbls
DVp_Struct-lbls(v) ==  fst(snd(v))

Lemma: DVp_Struct-lbls_wf
[v:C_DVALUEp()]. DVp_Struct-lbls(v) ∈ Atom List supposing ↑DVp_Struct?(v)

Definition: DVp_Struct-struct
DVp_Struct-struct(v) ==  snd(snd(v))

Lemma: DVp_Struct-struct_wf
[v:C_DVALUEp()]. DVp_Struct-struct(v) ∈ {a:Atom| (a ∈ DVp_Struct-lbls(v))}  ⟶ C_DVALUEp() supposing ↑DVp_Struct?(v)

Lemma: C_DVALUEp-induction
[P:C_DVALUEp() ⟶ ℙ]
  ((∀x:Unit. P[DVp_Null(x)])
   (∀int:ℤP[DVp_Int(int)])
   (∀ptr:C_LVALUE()?. P[DVp_Pointer(ptr)])
   (∀lower,upper:ℤ. ∀arr:{lower..upper-} ⟶ C_DVALUEp().
        ((∀u:{lower..upper-}. P[arr u])  P[DVp_Array(lower;upper;arr)]))
   (∀lbls:Atom List. ∀struct:{a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp().
        ((∀u:{a:Atom| (a ∈ lbls)} P[struct u])  P[DVp_Struct(lbls;struct)]))
   {∀v:C_DVALUEp(). P[v]})

Lemma: C_DVALUEp-definition
[A:Type]. ∀[R:A ⟶ C_DVALUEp() ⟶ ℙ].
  ((∀x:Unit. {x1:A| R[x1;DVp_Null(x)]} )
   (∀int:ℤ{x:A| R[x;DVp_Int(int)]} )
   (∀ptr:C_LVALUE()?. {x:A| R[x;DVp_Pointer(ptr)]} )
   (∀lower,upper:ℤ. ∀arr:{lower..upper-} ⟶ C_DVALUEp().
        ((∀u:{lower..upper-}. {x:A| R[x;arr u]}  {x:A| R[x;DVp_Array(lower;upper;arr)]} ))
   (∀lbls:Atom List. ∀struct:{a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp().
        ((∀u:{a:Atom| (a ∈ lbls)} {x:A| R[x;struct u]}  {x:A| R[x;DVp_Struct(lbls;struct)]} ))
   {∀v:C_DVALUEp(). {x:A| R[x;v]} })

Definition: C_DVALUEp_ind
C_DVALUEp_ind(v;
              DVp_Null(x) Null[x];
              DVp_Int(int) Int[int];
              DVp_Pointer(ptr) Pointer[ptr];
              DVp_Array(lower,upper,arr) rec1.Array[lower; upper; arr; rec1];
              DVp_Struct(lbls,struct) rec2.Struct[lbls; struct; rec2])  ==
  fix((λC_DVALUEp_ind,v. let lbl,v1 
                         in if lbl="Null" then Null[Ax]
                            if lbl="Int" then Int[v1]
                            if lbl="Pointer" then case v1 of inl(x) => Pointer[inl x] inr(y) => Pointer[inr Ax ]
                            if lbl="Array"
                              then let lower,v2 v1 
                                   in let upper,v3 v2 
                                      in Array[lower; upper; v3; λu.(C_DVALUEp_ind (v3 u))]
                            if lbl="Struct" then let lbls,v2 v1 in Struct[lbls; v2; λu.(C_DVALUEp_ind (v2 u))]
                            else Ax
                            fi )) 
  v

Lemma: C_DVALUEp_ind_wf
[A:Type]. ∀[R:A ⟶ C_DVALUEp() ⟶ ℙ]. ∀[v:C_DVALUEp()]. ∀[Null:x:Unit ⟶ {x1:A| R[x1;DVp_Null(x)]} ].
[Int:int:ℤ ⟶ {x:A| R[x;DVp_Int(int)]} ]. ∀[Pointer:ptr:(C_LVALUE()?) ⟶ {x:A| R[x;DVp_Pointer(ptr)]} ].
[Array:lower:ℤ
        ⟶ upper:ℤ
        ⟶ arr:({lower..upper-} ⟶ C_DVALUEp())
        ⟶ (u:{lower..upper-} ⟶ {x:A| R[x;arr u]} )
        ⟶ {x:A| R[x;DVp_Array(lower;upper;arr)]} ]. ∀[Struct:lbls:(Atom List)
                                                             ⟶ struct:({a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp())
                                                             ⟶ (u:{a:Atom| (a ∈ lbls)}  ⟶ {x:A| R[x;struct u]} )
                                                             ⟶ {x:A| R[x;DVp_Struct(lbls;struct)]} ].
  (C_DVALUEp_ind(v;
                 DVp_Null(x) Null[x];
                 DVp_Int(int) Int[int];
                 DVp_Pointer(ptr) Pointer[ptr];
                 DVp_Array(lower,upper,arr) rec1.Array[lower;upper;arr;rec1];
                 DVp_Struct(lbls,struct) rec2.Struct[lbls;struct;rec2])  ∈ {x:A| R[x;v]} )

Lemma: C_DVALUEp_ind_wf_simple
[A:Type]. ∀[v:C_DVALUEp()]. ∀[Null:x:Unit ⟶ A]. ∀[Int:int:ℤ ⟶ A]. ∀[Pointer:ptr:(C_LVALUE()?) ⟶ A].
[Array:lower:ℤ ⟶ upper:ℤ ⟶ arr:({lower..upper-} ⟶ C_DVALUEp()) ⟶ (u:{lower..upper-} ⟶ A) ⟶ A].
[Struct:lbls:(Atom List) ⟶ struct:({a:Atom| (a ∈ lbls)}  ⟶ C_DVALUEp()) ⟶ (u:{a:Atom| (a ∈ lbls)}  ⟶ A) ⟶ A].
  (C_DVALUEp_ind(v;
                 DVp_Null(x) Null[x];
                 DVp_Int(int) Int[int];
                 DVp_Pointer(ptr) Pointer[ptr];
                 DVp_Array(lower,upper,arr) rec1.Array[lower;upper;arr;rec1];
                 DVp_Struct(lbls,struct) rec2.Struct[lbls;struct;rec2])  ∈ A)

Definition: C_TYPE_vs_DVALp
C_TYPE_vs_DVALp(env;ctyp) ==
  C_TYPE_ind(ctyp
  Void=>λdval.ff
  Int=>λdval.DVp_Int?(dval)
  Struct(fields)=>r.λdval.if DVp_Struct?(dval)
                          then let lbls DVp_Struct-lbls(dval) in
                                let DVp_Struct-struct(dval) in
                                bdd-all(||fields||;i.eval fst(fields[i]) in
                                                     a ∈b lbls ∧b (r (g a)))
                          else ff
                          fi 
  Array(n,elems)=>recA.λdval.if DVp_Array?(dval)
                             then let DVp_Array-lower(dval) in
                                   let DVp_Array-upper(dval) in
                                   let DVp_Array-arr(dval) in
                                   (n =z a) ∧b (∀i∈upto(n).recA (f (a i)))_b
                             else ff
                             fi 
  Pointer(typ)=>recP.λdval.if DVp_Pointer?(dval)
                           then let ptr DVp_Pointer-ptr(dval) in
                                    if isl(ptr)
                                    then let lval outl(ptr) in
                                             if isl(C_TYPE-of-LVALUE(env;lval))
                                             then C_TYPE_eq(outl(C_TYPE-of-LVALUE(env;lval));typ)
                                             else ff
                                             fi 
                                    else tt
                                    fi 
                           else ff
                           fi )

Lemma: C_TYPE_vs_DVALp_wf
env:C_TYPE_env(). ∀ctyp:C_TYPE().  (C_TYPE_vs_DVALp(env;ctyp) ∈ C_DVALUEp() ⟶ 𝔹)

Definition: C_STOREp
C_STOREp() ==  C_LOCATION() ⟶ (C_DVALUEp()?)

Lemma: C_STOREp_wf
C_STOREp() ∈ Type

Definition: C_STOREp-welltyped
C_STOREp-welltyped(env;store) ==
  ∀loc:C_LOCATION()
    if isl(env loc)
    then ↑(isl(store loc) ∧b (C_TYPE_vs_DVALp(env;outl(env loc)) outl(store loc)))
    else ↑isr(store loc)
    fi 

Lemma: C_STOREp-welltyped_wf
env:C_TYPE_env(). ∀store:C_STOREp().  (C_STOREp-welltyped(env;store) ∈ ℙ)

Lemma: C_Array_vs_DVALp
store:C_STOREp(). ∀ctyp:C_TYPE(). ∀env:C_TYPE_env(). ∀dval:C_DVALUEp().
  (C_STOREp-welltyped(env;store)
   (↑C_Array?(ctyp))
   C_TYPE_vs_DVALp(env;ctyp) dval 
     if DVp_Array?(dval)
       then let DVp_Array-lower(dval) in
             let DVp_Array-upper(dval) in
             let DVp_Array-arr(dval) in
             (C_Array-length(ctyp) =z a)
             ∧b (∀i∈upto(C_Array-length(ctyp)).C_TYPE_vs_DVALp(env;C_Array-elems(ctyp)) (f (a i)))_b
       else ff
       fi )

Lemma: C_Array-elem_vs_DVALp
store:C_STOREp(). ∀ctyp:C_TYPE(). ∀env:C_TYPE_env(). ∀dval:C_DVALUEp(). ∀n:ℤ.
  (C_STOREp-welltyped(env;store)
   (↑C_Array?(ctyp))
   (0 ≤ n)
   n < C_Array-length(ctyp)
   (↑(C_TYPE_vs_DVALp(env;ctyp) dval))
   (↑(C_TYPE_vs_DVALp(env;C_Array-elems(ctyp)) (DVp_Array-arr(dval) (DVp_Array-lower(dval) n)))))

Lemma: C_Struct_vs_DVALp
store:C_STOREp(). ∀ctyp:C_TYPE(). ∀env:C_TYPE_env(). ∀dval:C_DVALUEp().
  (C_STOREp-welltyped(env;store)
   (↑C_Struct?(ctyp))
   C_TYPE_vs_DVALp(env;ctyp) dval 
     if DVp_Struct?(dval)
       then let map(λp.<fst(p), C_TYPE_vs_DVALp(env;snd(p))>;C_Struct-fields(ctyp)) in
             let lbls DVp_Struct-lbls(dval) in
             let DVp_Struct-struct(dval) in
             (∀p∈r.let a,wt 
                   in a ∈b lbls ∧b (wt (g a)))_b
       else ff
       fi )

Definition: C_the_value_p
C_the_value_p(store;lval) ==
  case lval is  
  Ground(loc) => store loc  
  a[idx] => let val_a case of in if isl(val_a) then DVp_Array-arr(outl(val_a)) idx else inr ⋅  fi   
  sval.comp =>  let val_s case of sval in if isl(val_s) then DVp_Struct-struct(outl(val_s)) comp else inr ⋅  fi )

Definition: memb22
memb22(T;t) ==  eq22(T; t; t)

Lemma: BNF-list-case0
ms:ℤ List. (imax-list([0 ms]) ∈ ℕ)

Lemma: BNF-list-case1
ms:ℤ List. ∀n:ℕ.  (imax-list([0 ms]) n ∈ ℕ)

Definition: MultiTreeco
MultiTreeco(T) ==
  corec(X.lbl:Atom × if lbl =a "Node" then labels:{L:Atom List| 0 < ||L||}  × ({a:Atom| (a ∈ labels)}  ⟶ X)
                     if lbl =a "Leaf" then T
                     else Void
                     fi )

Lemma: MultiTreeco_wf
[T:Type]. (MultiTreeco(T) ∈ Type)

Lemma: MultiTreeco-ext
[T:Type]
  MultiTreeco(T) ≡ lbl:Atom × if lbl =a "Node" then labels:{L:Atom List| 0 < ||L||}  × ({a:Atom| (a ∈ labels)}  ⟶ Multi\000CTreeco(T))
                              if lbl =a "Leaf" then T
                              else Void
                              fi 

Definition: MultiTreeco_size
MultiTreeco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Node" then + Σ(size ((snd(x)) fst(x)[a]) a < ||fst(x)||)
                   if lbl =a "Leaf" then 0
                   else 0
                   fi )) 
  p

Lemma: MultiTreeco_size_wf
[T:Type]. ∀[p:MultiTreeco(T)].  (MultiTreeco_size(p) ∈ partial(ℕ))

Definition: MultiTree
MultiTree(T) ==  {p:MultiTreeco(T)| (MultiTreeco_size(p))↓

Lemma: MultiTree_wf
[T:Type]. (MultiTree(T) ∈ Type)

Definition: MultiTree_size
MultiTree_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Node" then + Σ(size ((snd(x)) fst(x)[a]) a < ||fst(x)||)
                   if lbl =a "Leaf" then 0
                   else 0
                   fi )) 
  p

Lemma: MultiTree_size_wf
[T:Type]. ∀[p:MultiTree(T)].  (MultiTree_size(p) ∈ ℕ)

Lemma: MultiTree-ext
[T:Type]
  MultiTree(T) ≡ lbl:Atom × if lbl =a "Node" then labels:{L:Atom List| 0 < ||L||}  × ({a:Atom| (a ∈ labels)}  ⟶ MultiTr\000Cee(T))
                            if lbl =a "Leaf" then T
                            else Void
                            fi 

Definition: MTree_Node
MTree_Node(labels;children) ==  <"Node", labels, children>

Lemma: MTree_Node_wf
[T:Type]. ∀[labels:{L:Atom List| 0 < ||L||} ]. ∀[children:{a:Atom| (a ∈ labels)}  ⟶ MultiTree(T)].
  (MTree_Node(labels;children) ∈ MultiTree(T))

Definition: MTree_Leaf
MTree_Leaf(val) ==  <"Leaf", val>

Lemma: MTree_Leaf_wf
[T:Type]. ∀[val:T].  (MTree_Leaf(val) ∈ MultiTree(T))

Definition: MTree_Node?
MTree_Node?(v) ==  fst(v) =a "Node"

Lemma: MTree_Node?_wf
[T:Type]. ∀[v:MultiTree(T)].  (MTree_Node?(v) ∈ 𝔹)

Definition: MTree_Node-labels
MTree_Node-labels(v) ==  fst(snd(v))

Lemma: MTree_Node-labels_wf
[T:Type]. ∀[v:MultiTree(T)].  MTree_Node-labels(v) ∈ {L:Atom List| 0 < ||L||}  supposing ↑MTree_Node?(v)

Definition: MTree_Node-children
MTree_Node-children(v) ==  snd(snd(v))

Lemma: MTree_Node-children_wf
[T:Type]. ∀[v:MultiTree(T)].  MTree_Node-children(v) ∈ {a:Atom| (a ∈ MTree_Node-labels(v))}  ⟶ MultiTree(T) supposing \000C↑MTree_Node?(v)

Definition: MTree_Leaf?
MTree_Leaf?(v) ==  fst(v) =a "Leaf"

Lemma: MTree_Leaf?_wf
[T:Type]. ∀[v:MultiTree(T)].  (MTree_Leaf?(v) ∈ 𝔹)

Definition: MTree_Leaf-val
MTree_Leaf-val(v) ==  snd(v)

Lemma: MTree_Leaf-val_wf
[T:Type]. ∀[v:MultiTree(T)].  MTree_Leaf-val(v) ∈ supposing ↑MTree_Leaf?(v)

Lemma: MultiTree-induction
[T:Type]. ∀[P:MultiTree(T) ⟶ ℙ].
  ((∀labels:{L:Atom List| 0 < ||L||} . ∀children:{a:Atom| (a ∈ labels)}  ⟶ MultiTree(T).
      ((∀u:{a:Atom| (a ∈ labels)} P[children u])  P[MTree_Node(labels;children)]))
   (∀val:T. P[MTree_Leaf(val)])
   {∀v:MultiTree(T). P[v]})

Lemma: MultiTree-definition
[T,A:Type]. ∀[R:A ⟶ MultiTree(T) ⟶ ℙ].
  ((∀labels:{L:Atom List| 0 < ||L||} . ∀children:{a:Atom| (a ∈ labels)}  ⟶ MultiTree(T).
      ((∀u:{a:Atom| (a ∈ labels)} {x:A| R[x;children u]}  {x:A| R[x;MTree_Node(labels;children)]} ))
   (∀val:T. {x:A| R[x;MTree_Leaf(val)]} )
   {∀v:MultiTree(T). {x:A| R[x;v]} })

Definition: MultiTree_ind
MultiTree_ind(v;
              MTree_Node(labels,children) rec1.Node[labels; children; rec1];
              MTree_Leaf(val) Leaf[val])  ==
  fix((λMultiTree_ind,v. let lbl,v1 
                         in if lbl="Node" then let labels,v2 v1 in Node[labels; v2; λu.(MultiTree_ind (v2 u))]
                            if lbl="Leaf" then Leaf[v1]
                            else Ax
                            fi )) 
  v

Lemma: MultiTree_ind_wf
[T,A:Type]. ∀[R:A ⟶ MultiTree(T) ⟶ ℙ]. ∀[v:MultiTree(T)]. ∀[Node:labels:{L:Atom List| 0 < ||L||} 
                                                                    ⟶ children:({a:Atom| (a ∈ labels)}  ⟶ MultiTree(T)\000C)
                                                                    ⟶ (u:{a:Atom| (a ∈ labels)}  ⟶ {x:A| R[x;children \000Cu]} )
                                                                    ⟶ {x:A| R[x;MTree_Node(labels;children)]} ].
[Leaf:val:T ⟶ {x:A| R[x;MTree_Leaf(val)]} ].
  (MultiTree_ind(v;
                 MTree_Node(labels,children) rec1.Node[labels;children;rec1];
                 MTree_Leaf(val) Leaf[val])  ∈ {x:A| R[x;v]} )

Lemma: MultiTree_ind_wf_simple
[T,A:Type]. ∀[v:MultiTree(T)]. ∀[Node:labels:{L:Atom List| 0 < ||L||} 
                                       ⟶ children:({a:Atom| (a ∈ labels)}  ⟶ MultiTree(T))
                                       ⟶ (u:{a:Atom| (a ∈ labels)}  ⟶ A)
                                       ⟶ A]. ∀[Leaf:val:T ⟶ A].
  (MultiTree_ind(v;
                 MTree_Node(labels,children) rec1.Node[labels;children;rec1];
                 MTree_Leaf(val) Leaf[val])  ∈ A)

Definition: MTree-rank
MTree-rank(t) ==
  fix((λMTree-rank,t. if MTree_Leaf?(t)
                     then 0
                     else imax-list(map(λa.(MTree-rank (MTree_Node-children(t) a));MTree_Node-labels(t))) 1
                     fi )) 
  t

Lemma: MTree-rank_wf
T:Type. ∀tr:MultiTree(T).  (MTree-rank(tr) ∈ ℕ)

Lemma: MTree-induction2
[T:Type]. ∀[P:MultiTree(T) ⟶ ℙ].
  ((∀labels:{L:Atom List| 0 < ||L||} . ∀children:{a:Atom| (a ∈ labels)}  ⟶ MultiTree(T).
      ((∀a∈labels.P[children a])  P[MTree_Node(labels;children)]))
   (∀val:T. P[MTree_Leaf(val)])
   {∀x:MultiTree(T). P[x]})

Definition: MMTreeco
MMTreeco(T) ==  corec(X.lbl:Atom × if lbl =a "Leaf" then if lbl =a "Node" then List List else Void fi )

Lemma: MMTreeco_wf
[T:Type]. (MMTreeco(T) ∈ Type)

Lemma: MMTreeco-ext
[T:Type]. MMTreeco(T) ≡ lbl:Atom × if lbl =a "Leaf" then if lbl =a "Node" then MMTreeco(T) List List else Void fi 

Definition: MMTreeco_size
MMTreeco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Node" then + Σ(size x[i][i1] i1 < ||x[i]||) i < ||x||)
                   else 0
                   fi )) 
  p

Lemma: MMTreeco_size_wf
[T:Type]. ∀[p:MMTreeco(T)].  (MMTreeco_size(p) ∈ partial(ℕ))

Definition: MMTree
MMTree(T) ==  {p:MMTreeco(T)| (MMTreeco_size(p))↓

Lemma: MMTree_wf
[T:Type]. (MMTree(T) ∈ Type)

Definition: MMTree_size
MMTree_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Node" then + Σ(size x[i][i1] i1 < ||x[i]||) i < ||x||)
                   else 0
                   fi )) 
  p

Lemma: MMTree_size_wf
[T:Type]. ∀[p:MMTree(T)].  (MMTree_size(p) ∈ ℕ)

Lemma: MMTree-ext
[T:Type]. MMTree(T) ≡ lbl:Atom × if lbl =a "Leaf" then if lbl =a "Node" then MMTree(T) List List else Void fi 

Definition: MMTree_Leaf
MMTree_Leaf(val) ==  <"Leaf", val>

Lemma: MMTree_Leaf_wf
[T:Type]. ∀[val:T].  (MMTree_Leaf(val) ∈ MMTree(T))

Definition: MMTree_Node
MMTree_Node(forest) ==  <"Node", forest>

Lemma: MMTree_Node_wf
[T:Type]. ∀[forest:MMTree(T) List List].  (MMTree_Node(forest) ∈ MMTree(T))

Definition: MMTree_Leaf?
MMTree_Leaf?(v) ==  fst(v) =a "Leaf"

Lemma: MMTree_Leaf?_wf
[T:Type]. ∀[v:MMTree(T)].  (MMTree_Leaf?(v) ∈ 𝔹)

Definition: MMTree_Leaf-val
MMTree_Leaf-val(v) ==  snd(v)

Lemma: MMTree_Leaf-val_wf
[T:Type]. ∀[v:MMTree(T)].  MMTree_Leaf-val(v) ∈ supposing ↑MMTree_Leaf?(v)

Definition: MMTree_Node?
MMTree_Node?(v) ==  fst(v) =a "Node"

Lemma: MMTree_Node?_wf
[T:Type]. ∀[v:MMTree(T)].  (MMTree_Node?(v) ∈ 𝔹)

Definition: MMTree_Node-forest
MMTree_Node-forest(v) ==  snd(v)

Lemma: MMTree_Node-forest_wf
[T:Type]. ∀[v:MMTree(T)].  MMTree_Node-forest(v) ∈ MMTree(T) List List supposing ↑MMTree_Node?(v)

Lemma: MMTree-induction
[T:Type]. ∀[P:MMTree(T) ⟶ ℙ].
  ((∀val:T. P[MMTree_Leaf(val)])
   (∀forest:MMTree(T) List List. ((∀u∈forest.(∀u1∈u.P[u1]))  P[MMTree_Node(forest)]))
   {∀v:MMTree(T). P[v]})

Lemma: MMTree-definition
[T,A:Type]. ∀[R:A ⟶ MMTree(T) ⟶ ℙ].
  ((∀val:T. {x:A| R[x;MMTree_Leaf(val)]} )
   (∀forest:MMTree(T) List List. ((∀u∈forest.(∀u1∈u.{x:A| R[x;u1]} ))  {x:A| R[x;MMTree_Node(forest)]} ))
   {∀v:MMTree(T). {x:A| R[x;v]} })

Definition: MMTree-rank
MMTree-rank(t) ==
  fix((λMMTree-rank,t. if MMTree_Leaf?(t)
                      then 0
                      else imax-list([0 map(λl.imax-list([0 map(λs.(MMTree-rank s);l)]);MMTree_Node-forest(t))])
                      fi )) 
  t

Lemma: MMTree-rank_wf
T:Type. ∀t:MMTree(T).  (MMTree-rank(t) ∈ ℕ)

Definition: RankEx1co
RankEx1co(T) ==
  corec(X.lbl:Atom × if lbl =a "Leaf" then T
                     if lbl =a "Prod" then X × X
                     if lbl =a "ProdL" then T × X
                     if lbl =a "ProdR" then X × T
                     if lbl =a "List" then List
                     else Void
                     fi )

Lemma: RankEx1co_wf
[T:Type]. (RankEx1co(T) ∈ Type)

Lemma: RankEx1co-ext
[T:Type]
  RankEx1co(T) ≡ lbl:Atom × if lbl =a "Leaf" then T
                            if lbl =a "Prod" then RankEx1co(T) × RankEx1co(T)
                            if lbl =a "ProdL" then T × RankEx1co(T)
                            if lbl =a "ProdR" then RankEx1co(T) × T
                            if lbl =a "List" then RankEx1co(T) List
                            else Void
                            fi 

Definition: RankEx1co_size
RankEx1co_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Prod" then (size (fst(x))) (size (snd(x)))
                   if lbl =a "ProdL" then (size (snd(x)))
                   if lbl =a "ProdR" then (size (fst(x)))
                   if lbl =a "List" then + Σ(size x[i] i < ||x||)
                   else 0
                   fi )) 
  p

Lemma: RankEx1co_size_wf
[T:Type]. ∀[p:RankEx1co(T)].  (RankEx1co_size(p) ∈ partial(ℕ))

Definition: RankEx1
RankEx1(T) ==  {p:RankEx1co(T)| (RankEx1co_size(p))↓

Lemma: RankEx1_wf
[T:Type]. (RankEx1(T) ∈ Type)

Definition: RankEx1_size
RankEx1_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Prod" then (size (fst(x))) (size (snd(x)))
                   if lbl =a "ProdL" then (size (snd(x)))
                   if lbl =a "ProdR" then (size (fst(x)))
                   if lbl =a "List" then + Σ(size x[i] i < ||x||)
                   else 0
                   fi )) 
  p

Lemma: RankEx1_size_wf
[T:Type]. ∀[p:RankEx1(T)].  (RankEx1_size(p) ∈ ℕ)

Lemma: RankEx1-ext
[T:Type]
  RankEx1(T) ≡ lbl:Atom × if lbl =a "Leaf" then T
                          if lbl =a "Prod" then RankEx1(T) × RankEx1(T)
                          if lbl =a "ProdL" then T × RankEx1(T)
                          if lbl =a "ProdR" then RankEx1(T) × T
                          if lbl =a "List" then RankEx1(T) List
                          else Void
                          fi 

Definition: RankEx1_Leaf
RankEx1_Leaf(leaf) ==  <"Leaf", leaf>

Lemma: RankEx1_Leaf_wf
[T:Type]. ∀[leaf:T].  (RankEx1_Leaf(leaf) ∈ RankEx1(T))

Definition: RankEx1_Prod
RankEx1_Prod(prod) ==  <"Prod", prod>

Lemma: RankEx1_Prod_wf
[T:Type]. ∀[prod:RankEx1(T) × RankEx1(T)].  (RankEx1_Prod(prod) ∈ RankEx1(T))

Definition: RankEx1_ProdL
RankEx1_ProdL(prodl) ==  <"ProdL", prodl>

Lemma: RankEx1_ProdL_wf
[T:Type]. ∀[prodl:T × RankEx1(T)].  (RankEx1_ProdL(prodl) ∈ RankEx1(T))

Definition: RankEx1_ProdR
RankEx1_ProdR(prodr) ==  <"ProdR", prodr>

Lemma: RankEx1_ProdR_wf
[T:Type]. ∀[prodr:RankEx1(T) × T].  (RankEx1_ProdR(prodr) ∈ RankEx1(T))

Definition: RankEx1_List
RankEx1_List(list) ==  <"List", list>

Lemma: RankEx1_List_wf
[T:Type]. ∀[list:RankEx1(T) List].  (RankEx1_List(list) ∈ RankEx1(T))

Definition: RankEx1_Leaf?
RankEx1_Leaf?(v) ==  fst(v) =a "Leaf"

Lemma: RankEx1_Leaf?_wf
[T:Type]. ∀[v:RankEx1(T)].  (RankEx1_Leaf?(v) ∈ 𝔹)

Definition: RankEx1_Leaf-leaf
RankEx1_Leaf-leaf(v) ==  snd(v)

Lemma: RankEx1_Leaf-leaf_wf
[T:Type]. ∀[v:RankEx1(T)].  RankEx1_Leaf-leaf(v) ∈ supposing ↑RankEx1_Leaf?(v)

Definition: RankEx1_Prod?
RankEx1_Prod?(v) ==  fst(v) =a "Prod"

Lemma: RankEx1_Prod?_wf
[T:Type]. ∀[v:RankEx1(T)].  (RankEx1_Prod?(v) ∈ 𝔹)

Definition: RankEx1_Prod-prod
RankEx1_Prod-prod(v) ==  snd(v)

Lemma: RankEx1_Prod-prod_wf
[T:Type]. ∀[v:RankEx1(T)].  RankEx1_Prod-prod(v) ∈ RankEx1(T) × RankEx1(T) supposing ↑RankEx1_Prod?(v)

Definition: RankEx1_ProdL?
RankEx1_ProdL?(v) ==  fst(v) =a "ProdL"

Lemma: RankEx1_ProdL?_wf
[T:Type]. ∀[v:RankEx1(T)].  (RankEx1_ProdL?(v) ∈ 𝔹)

Definition: RankEx1_ProdL-prodl
RankEx1_ProdL-prodl(v) ==  snd(v)

Lemma: RankEx1_ProdL-prodl_wf
[T:Type]. ∀[v:RankEx1(T)].  RankEx1_ProdL-prodl(v) ∈ T × RankEx1(T) supposing ↑RankEx1_ProdL?(v)

Definition: RankEx1_ProdR?
RankEx1_ProdR?(v) ==  fst(v) =a "ProdR"

Lemma: RankEx1_ProdR?_wf
[T:Type]. ∀[v:RankEx1(T)].  (RankEx1_ProdR?(v) ∈ 𝔹)

Definition: RankEx1_ProdR-prodr
RankEx1_ProdR-prodr(v) ==  snd(v)

Lemma: RankEx1_ProdR-prodr_wf
[T:Type]. ∀[v:RankEx1(T)].  RankEx1_ProdR-prodr(v) ∈ RankEx1(T) × supposing ↑RankEx1_ProdR?(v)

Definition: RankEx1_List?
RankEx1_List?(v) ==  fst(v) =a "List"

Lemma: RankEx1_List?_wf
[T:Type]. ∀[v:RankEx1(T)].  (RankEx1_List?(v) ∈ 𝔹)

Definition: RankEx1_List-list
RankEx1_List-list(v) ==  snd(v)

Lemma: RankEx1_List-list_wf
[T:Type]. ∀[v:RankEx1(T)].  RankEx1_List-list(v) ∈ RankEx1(T) List supposing ↑RankEx1_List?(v)

Lemma: RankEx1-induction
[T:Type]. ∀[P:RankEx1(T) ⟶ ℙ].
  ((∀leaf:T. P[RankEx1_Leaf(leaf)])
   (∀prod:RankEx1(T) × RankEx1(T). (let u,u1 prod in P[u] ∧ P[u1]  P[RankEx1_Prod(prod)]))
   (∀prodl:T × RankEx1(T). (let u,u1 prodl in P[u1]  P[RankEx1_ProdL(prodl)]))
   (∀prodr:RankEx1(T) × T. (let u,u1 prodr in P[u]  P[RankEx1_ProdR(prodr)]))
   (∀list:RankEx1(T) List. ((∀u∈list.P[u])  P[RankEx1_List(list)]))
   {∀v:RankEx1(T). P[v]})

Lemma: RankEx1-definition
[T,A:Type]. ∀[R:A ⟶ RankEx1(T) ⟶ ℙ].
  ((∀leaf:T. {x:A| R[x;RankEx1_Leaf(leaf)]} )
   (∀prod:RankEx1(T) × RankEx1(T)
        (let u,u1 prod in {x:A| R[x;u]}  ∧ {x:A| R[x;u1]}   {x:A| R[x;RankEx1_Prod(prod)]} ))
   (∀prodl:T × RankEx1(T). (let u,u1 prodl in {x:A| R[x;u1]}   {x:A| R[x;RankEx1_ProdL(prodl)]} ))
   (∀prodr:RankEx1(T) × T. (let u,u1 prodr in {x:A| R[x;u]}   {x:A| R[x;RankEx1_ProdR(prodr)]} ))
   (∀list:RankEx1(T) List. ((∀u∈list.{x:A| R[x;u]}  {x:A| R[x;RankEx1_List(list)]} ))
   {∀v:RankEx1(T). {x:A| R[x;v]} })

Definition: RankEx1_ind
RankEx1_ind(v;
            RankEx1_Leaf(leaf) Leaf[leaf];
            RankEx1_Prod(prod) rec1.Prod[prod; rec1];
            RankEx1_ProdL(prodl) rec2.ProdL[prodl; rec2];
            RankEx1_ProdR(prodr) rec3.ProdR[prodr; rec3];
            RankEx1_List(list) rec4.List[list; rec4])  ==
  fix((λRankEx1_ind,v. let lbl,v1 
                       in if lbl="Leaf" then Leaf[v1]
                          if lbl="Prod" then let v2,v3 v1 in Prod[<v2, v3>; <RankEx1_ind v2, RankEx1_ind v3>]
                          if lbl="ProdL" then let v2,v3 v1 in ProdL[<v2, v3>RankEx1_ind v3]
                          if lbl="ProdR" then let v2,v3 v1 in ProdR[<v2, v3>RankEx1_ind v2]
                          if lbl="List" then List[v1; λi.(RankEx1_ind v1[i])]
                          else Ax
                          fi )) 
  v

Lemma: RankEx1_ind_wf
[T,A:Type]. ∀[R:A ⟶ RankEx1(T) ⟶ ℙ]. ∀[v:RankEx1(T)]. ∀[Leaf:leaf:T ⟶ {x:A| R[x;RankEx1_Leaf(leaf)]} ].
[Prod:prod:(RankEx1(T) × RankEx1(T))
       ⟶ let u,u1 prod 
          in {x:A| R[x;u]}  ∧ {x:A| R[x;u1]} 
       ⟶ {x:A| R[x;RankEx1_Prod(prod)]} ]. ∀[ProdL:prodl:(T × RankEx1(T))
                                                   ⟶ let u,u1 prodl 
                                                      in {x:A| R[x;u1]} 
                                                   ⟶ {x:A| R[x;RankEx1_ProdL(prodl)]} ].
[ProdR:prodr:(RankEx1(T) × T) ⟶ let u,u1 prodr in {x:A| R[x;u]}  ⟶ {x:A| R[x;RankEx1_ProdR(prodr)]} ].
[List:list:(RankEx1(T) List) ⟶ (∀u∈list.{x:A| R[x;u]} ) ⟶ {x:A| R[x;RankEx1_List(list)]} ].
  (RankEx1_ind(v;
               RankEx1_Leaf(leaf) Leaf[leaf];
               RankEx1_Prod(prod) rec1.Prod[prod;rec1];
               RankEx1_ProdL(prodl) rec2.ProdL[prodl;rec2];
               RankEx1_ProdR(prodr) rec3.ProdR[prodr;rec3];
               RankEx1_List(list) rec4.List[list;rec4])  ∈ {x:A| R[x;v]} )

Lemma: RankEx1_ind_wf_simple
[T,A:Type]. ∀[v:RankEx1(T)]. ∀[Leaf:leaf:T ⟶ A]. ∀[Prod:prod:(RankEx1(T) × RankEx1(T))
                                                          ⟶ let u,u1 prod 
                                                             in A ∧ A
                                                          ⟶ A]. ∀[ProdL:prodl:(T × RankEx1(T))
                                                                         ⟶ let u,u1 prodl 
                                                                            in A
                                                                         ⟶ A]. ∀[ProdR:prodr:(RankEx1(T) × T)
                                                                                        ⟶ let u,u1 prodr 
                                                                                           in A
                                                                                        ⟶ A].
[List:list:(RankEx1(T) List) ⟶ (∀u∈list.A) ⟶ A].
  (RankEx1_ind(v;
               RankEx1_Leaf(leaf) Leaf[leaf];
               RankEx1_Prod(prod) rec1.Prod[prod;rec1];
               RankEx1_ProdL(prodl) rec2.ProdL[prodl;rec2];
               RankEx1_ProdR(prodr) rec3.ProdR[prodr;rec3];
               RankEx1_List(list) rec4.List[list;rec4])  ∈ A)

Definition: rank-Ex1
rank-Ex1(t) ==
  fix((λrank-Ex1,t. if RankEx1_Leaf?(t) then 1
                   if RankEx1_Prod?(t)
                     then imax(rank-Ex1 (fst(RankEx1_Prod-prod(t)));rank-Ex1 (snd(RankEx1_Prod-prod(t)))) 1
                   if RankEx1_ProdL?(t) then (rank-Ex1 (snd(RankEx1_ProdL-prodl(t)))) 1
                   if RankEx1_ProdR?(t) then (rank-Ex1 (fst(RankEx1_ProdR-prodr(t)))) 1
                   else imax-list([0 map(λu.(rank-Ex1 u);RankEx1_List-list(t))]) 1
                   fi )) 
  t

Lemma: rank-Ex1_wf
[T:Type]. ∀[t:RankEx1(T)].  (rank-Ex1(t) ∈ ℕ)

Definition: RankEx2co
RankEx2co(S;T) ==
  corec(X.lbl:Atom × if lbl =a "LeafT" then T
                     if lbl =a "LeafS" then S
                     if lbl =a "Prod" then X × S × T
                     if lbl =a "Union" then S × X
                     if lbl =a "ListProd" then (S × X) List
                     if lbl =a "UnionList" then (X List)
                     else Void
                     fi )

Lemma: RankEx2co_wf
[S,T:Type].  (RankEx2co(S;T) ∈ Type)

Lemma: RankEx2co-ext
[S,T:Type].
  RankEx2co(S;T) ≡ lbl:Atom × if lbl =a "LeafT" then T
                              if lbl =a "LeafS" then S
                              if lbl =a "Prod" then RankEx2co(S;T) × S × T
                              if lbl =a "Union" then S × RankEx2co(S;T) RankEx2co(S;T)
                              if lbl =a "ListProd" then (S × RankEx2co(S;T)) List
                              if lbl =a "UnionList" then (RankEx2co(S;T) List)
                              else Void
                              fi 

Definition: RankEx2co_size
RankEx2co_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "LeafT" then 0
                   if lbl =a "LeafS" then 0
                   if lbl =a "Prod" then (size (fst(fst(x))))
                   if lbl =a "Union" then case of inl(a) => size (snd(a)) inr(b) => size b
                   if lbl =a "ListProd" then + Σ(size (snd(x[i])) i < ||x||)
                   if lbl =a "UnionList" then case of inl(a) => inr(b) => Σ(size b[i] i < ||b||)
                   else 0
                   fi )) 
  p

Lemma: RankEx2co_size_wf
[S,T:Type]. ∀[p:RankEx2co(S;T)].  (RankEx2co_size(p) ∈ partial(ℕ))

Definition: RankEx2
RankEx2(S;T) ==  {p:RankEx2co(S;T)| (RankEx2co_size(p))↓

Lemma: RankEx2_wf
[S,T:Type].  (RankEx2(S;T) ∈ Type)

Definition: RankEx2_size
RankEx2_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "LeafT" then 0
                   if lbl =a "LeafS" then 0
                   if lbl =a "Prod" then (size (fst(fst(x))))
                   if lbl =a "Union" then case of inl(a) => size (snd(a)) inr(b) => size b
                   if lbl =a "ListProd" then + Σ(size (snd(x[i])) i < ||x||)
                   if lbl =a "UnionList" then case of inl(a) => inr(b) => Σ(size b[i] i < ||b||)
                   else 0
                   fi )) 
  p

Lemma: RankEx2_size_wf
[S,T:Type]. ∀[p:RankEx2(S;T)].  (RankEx2_size(p) ∈ ℕ)

Lemma: RankEx2-ext
[S,T:Type].
  RankEx2(S;T) ≡ lbl:Atom × if lbl =a "LeafT" then T
                            if lbl =a "LeafS" then S
                            if lbl =a "Prod" then RankEx2(S;T) × S × T
                            if lbl =a "Union" then S × RankEx2(S;T) RankEx2(S;T)
                            if lbl =a "ListProd" then (S × RankEx2(S;T)) List
                            if lbl =a "UnionList" then (RankEx2(S;T) List)
                            else Void
                            fi 

Definition: RankEx2_LeafT
RankEx2_LeafT(leaft) ==  <"LeafT", leaft>

Lemma: RankEx2_LeafT_wf
[S,T:Type]. ∀[leaft:T].  (RankEx2_LeafT(leaft) ∈ RankEx2(S;T))

Definition: RankEx2_LeafS
RankEx2_LeafS(leafs) ==  <"LeafS", leafs>

Lemma: RankEx2_LeafS_wf
[S,T:Type]. ∀[leafs:S].  (RankEx2_LeafS(leafs) ∈ RankEx2(S;T))

Definition: RankEx2_Prod
RankEx2_Prod(prod) ==  <"Prod", prod>

Lemma: RankEx2_Prod_wf
[S,T:Type]. ∀[prod:RankEx2(S;T) × S × T].  (RankEx2_Prod(prod) ∈ RankEx2(S;T))

Definition: RankEx2_Union
RankEx2_Union(union) ==  <"Union", union>

Lemma: RankEx2_Union_wf
[S,T:Type]. ∀[union:S × RankEx2(S;T) RankEx2(S;T)].  (RankEx2_Union(union) ∈ RankEx2(S;T))

Definition: RankEx2_ListProd
RankEx2_ListProd(listprod) ==  <"ListProd", listprod>

Lemma: RankEx2_ListProd_wf
[S,T:Type]. ∀[listprod:(S × RankEx2(S;T)) List].  (RankEx2_ListProd(listprod) ∈ RankEx2(S;T))

Definition: RankEx2_UnionList
RankEx2_UnionList(unionlist) ==  <"UnionList", unionlist>

Lemma: RankEx2_UnionList_wf
[S,T:Type]. ∀[unionlist:T (RankEx2(S;T) List)].  (RankEx2_UnionList(unionlist) ∈ RankEx2(S;T))

Definition: RankEx2_LeafT?
RankEx2_LeafT?(v) ==  fst(v) =a "LeafT"

Lemma: RankEx2_LeafT?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_LeafT?(v) ∈ 𝔹)

Definition: RankEx2_LeafT-leaft
RankEx2_LeafT-leaft(v) ==  snd(v)

Lemma: RankEx2_LeafT-leaft_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  RankEx2_LeafT-leaft(v) ∈ supposing ↑RankEx2_LeafT?(v)

Definition: RankEx2_LeafS?
RankEx2_LeafS?(v) ==  fst(v) =a "LeafS"

Lemma: RankEx2_LeafS?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_LeafS?(v) ∈ 𝔹)

Definition: RankEx2_LeafS-leafs
RankEx2_LeafS-leafs(v) ==  snd(v)

Lemma: RankEx2_LeafS-leafs_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  RankEx2_LeafS-leafs(v) ∈ supposing ↑RankEx2_LeafS?(v)

Definition: RankEx2_Prod?
RankEx2_Prod?(v) ==  fst(v) =a "Prod"

Lemma: RankEx2_Prod?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_Prod?(v) ∈ 𝔹)

Definition: RankEx2_Prod-prod
RankEx2_Prod-prod(v) ==  snd(v)

Lemma: RankEx2_Prod-prod_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  RankEx2_Prod-prod(v) ∈ RankEx2(S;T) × S × supposing ↑RankEx2_Prod?(v)

Definition: RankEx2_Union?
RankEx2_Union?(v) ==  fst(v) =a "Union"

Lemma: RankEx2_Union?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_Union?(v) ∈ 𝔹)

Definition: RankEx2_Union-union
RankEx2_Union-union(v) ==  snd(v)

Lemma: RankEx2_Union-union_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  RankEx2_Union-union(v) ∈ S × RankEx2(S;T) RankEx2(S;T) supposing ↑RankEx2_Union?(v)

Definition: RankEx2_ListProd?
RankEx2_ListProd?(v) ==  fst(v) =a "ListProd"

Lemma: RankEx2_ListProd?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_ListProd?(v) ∈ 𝔹)

Definition: RankEx2_ListProd-listprod
RankEx2_ListProd-listprod(v) ==  snd(v)

Lemma: RankEx2_ListProd-listprod_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  RankEx2_ListProd-listprod(v) ∈ (S × RankEx2(S;T)) List supposing ↑RankEx2_ListProd?(v)

Definition: RankEx2_UnionList?
RankEx2_UnionList?(v) ==  fst(v) =a "UnionList"

Lemma: RankEx2_UnionList?_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].  (RankEx2_UnionList?(v) ∈ 𝔹)

Definition: RankEx2_UnionList-unionlist
RankEx2_UnionList-unionlist(v) ==  snd(v)

Lemma: RankEx2_UnionList-unionlist_wf
[S,T:Type]. ∀[v:RankEx2(S;T)].
  RankEx2_UnionList-unionlist(v) ∈ (RankEx2(S;T) List) supposing ↑RankEx2_UnionList?(v)

Lemma: RankEx2-induction
[S,T:Type]. ∀[P:RankEx2(S;T) ⟶ ℙ].
  ((∀leaft:T. P[RankEx2_LeafT(leaft)])
   (∀leafs:S. P[RankEx2_LeafS(leafs)])
   (∀prod:RankEx2(S;T) × S × T. (let u,u1 prod in let u1,u2 in P[u1]  P[RankEx2_Prod(prod)]))
   (∀union:S × RankEx2(S;T) RankEx2(S;T)
        (case union of inl(u) => let u1,u2 in P[u2] inr(u1) => P[u1]  P[RankEx2_Union(union)]))
   (∀listprod:(S × RankEx2(S;T)) List. ((∀u∈listprod.let u1,u2 in P[u2])  P[RankEx2_ListProd(listprod)]))
   (∀unionlist:T (RankEx2(S;T) List)
        (case unionlist of inl(u) => True inr(u1) => (∀u∈u1.P[u])  P[RankEx2_UnionList(unionlist)]))
   {∀v:RankEx2(S;T). P[v]})

Lemma: RankEx2-definition
[S,T,A:Type]. ∀[R:A ⟶ RankEx2(S;T) ⟶ ℙ].
  ((∀leaft:T. {x:A| R[x;RankEx2_LeafT(leaft)]} )
   (∀leafs:S. {x:A| R[x;RankEx2_LeafS(leafs)]} )
   (∀prod:RankEx2(S;T) × S × T
        (let u,u1 prod in let u1,u2 in {x:A| R[x;u1]}   {x:A| R[x;RankEx2_Prod(prod)]} ))
   (∀union:S × RankEx2(S;T) RankEx2(S;T)
        (case union of inl(u) => let u1,u2 in {x:A| R[x;u2]}  inr(u1) => {x:A| R[x;u1]} 
         {x:A| R[x;RankEx2_Union(union)]} ))
   (∀listprod:(S × RankEx2(S;T)) List
        ((∀u∈listprod.let u1,u2 in {x:A| R[x;u2]}  {x:A| R[x;RankEx2_ListProd(listprod)]} ))
   (∀unionlist:T (RankEx2(S;T) List)
        (case unionlist of inl(u) => True inr(u1) => (∀u∈u1.{x:A| R[x;u]}  {x:A| R[x;RankEx2_UnionList(unionlist)]\000C} ))
   {∀v:RankEx2(S;T). {x:A| R[x;v]} })

Definition: RankEx2_ind
RankEx2_ind(v;
            RankEx2_LeafT(leaft) LeafT[leaft];
            RankEx2_LeafS(leafs) LeafS[leafs];
            RankEx2_Prod(prod) rec1.Prod[prod; rec1];
            RankEx2_Union(union) rec2.Union[union; rec2];
            RankEx2_ListProd(listprod) rec3.ListProd[listprod; rec3];
            RankEx2_UnionList(unionlist) rec4.UnionList[unionlist; rec4])  ==
  fix((λRankEx2_ind,v. let lbl,v1 
                       in if lbl="LeafT" then LeafT[v1]
                          if lbl="LeafS" then LeafS[v1]
                          if lbl="Prod" then let v2,v3 v1 in let v4,v5 v2 in Prod[<<v4, v5>v3>RankEx2_ind v4]
                          if lbl="Union"
                            then case v1
                                  of inl(x) =>
                                  let x1,x2 
                                  in Union[inl <x1, x2>RankEx2_ind x2]
                                  inr(y) =>
                                  Union[inr RankEx2_ind y]
                          if lbl="ListProd" then ListProd[v1; λi.let v2,v3 v1[i] in RankEx2_ind v3]
                          if lbl="UnionList"
                            then case v1
                                  of inl(x) =>
                                  UnionList[inl x; Ax]
                                  inr(y) =>
                                  UnionList[inr ; λi.(RankEx2_ind y[i])]
                          else Ax
                          fi )) 
  v

Lemma: RankEx2_ind_wf
[S,T,A:Type]. ∀[R:A ⟶ RankEx2(S;T) ⟶ ℙ]. ∀[v:RankEx2(S;T)]. ∀[LeafT:leaft:T ⟶ {x:A| R[x;RankEx2_LeafT(leaft)]} ].
[LeafS:leafs:S ⟶ {x:A| R[x;RankEx2_LeafS(leafs)]} ]. ∀[Prod:prod:(RankEx2(S;T) × S × T)
                                                             ⟶ let u,u1 prod 
                                                                in let u1,u2 
                                                                   in {x:A| R[x;u1]} 
                                                             ⟶ {x:A| R[x;RankEx2_Prod(prod)]} ].
[Union:union:(S × RankEx2(S;T) RankEx2(S;T))
        ⟶ case union of inl(u) => let u1,u2 in {x:A| R[x;u2]}  inr(u1) => {x:A| R[x;u1]} 
        ⟶ {x:A| R[x;RankEx2_Union(union)]} ]. ∀[ListProd:listprod:((S × RankEx2(S;T)) List)
                                                         ⟶ (∀u∈listprod.let u1,u2 
                                                                         in {x:A| R[x;u2]} )
                                                         ⟶ {x:A| R[x;RankEx2_ListProd(listprod)]} ].
[UnionList:unionlist:(T (RankEx2(S;T) List))
            ⟶ case unionlist of inl(u) => True inr(u1) => (∀u∈u1.{x:A| R[x;u]} )
            ⟶ {x:A| R[x;RankEx2_UnionList(unionlist)]} ].
  (RankEx2_ind(v;
               RankEx2_LeafT(leaft) LeafT[leaft];
               RankEx2_LeafS(leafs) LeafS[leafs];
               RankEx2_Prod(prod) rec1.Prod[prod;rec1];
               RankEx2_Union(union) rec2.Union[union;rec2];
               RankEx2_ListProd(listprod) rec3.ListProd[listprod;rec3];
               RankEx2_UnionList(unionlist) rec4.UnionList[unionlist;rec4])  ∈ {x:A| R[x;v]} )

Lemma: RankEx2_ind_wf_simple
[S,T,A:Type]. ∀[v:RankEx2(S;T)]. ∀[LeafT:leaft:T ⟶ A]. ∀[LeafS:leafs:S ⟶ A]. ∀[Prod:prod:(RankEx2(S;T) × S × T)
                                                                                       ⟶ let u,u1 prod 
                                                                                          in let u1,u2 
                                                                                             in A
                                                                                       ⟶ A].
[Union:union:(S × RankEx2(S;T) RankEx2(S;T)) ⟶ case union of inl(u) => let u1,u2 in inr(u1) => A ⟶ A].
[ListProd:listprod:((S × RankEx2(S;T)) List) ⟶ (∀u∈listprod.let u1,u2 in A) ⟶ A].
[UnionList:unionlist:(T (RankEx2(S;T) List)) ⟶ case unionlist of inl(u) => True inr(u1) => (∀u∈u1.A) ⟶ A].
  (RankEx2_ind(v;
               RankEx2_LeafT(leaft) LeafT[leaft];
               RankEx2_LeafS(leafs) LeafS[leafs];
               RankEx2_Prod(prod) rec1.Prod[prod;rec1];
               RankEx2_Union(union) rec2.Union[union;rec2];
               RankEx2_ListProd(listprod) rec3.ListProd[listprod;rec3];
               RankEx2_UnionList(unionlist) rec4.UnionList[unionlist;rec4])  ∈ A)

Lemma: RankEx2_ind-unroll
[S,T,A:Type]. ∀[R:A ⟶ RankEx2(S;T) ⟶ ℙ]. ∀[LeafT,LeafS,Prod,Union,ListProd,UnionList:Top]. ∀[t:RankEx2(S;T)].
  (RankEx2_ind(t;
               RankEx2_LeafT(leaft) LeafT[leaft];
               RankEx2_LeafS(leafs) LeafS[leafs];
               RankEx2_Prod(prod) rec1.Prod[prod;rec1];
               RankEx2_Union(union) rec2.Union[union;rec2];
               RankEx2_ListProd(listprod) rec3.ListProd[listprod;rec3];
               RankEx2_UnionList(unionlist) rec4.UnionList[unionlist;rec4])  
  let = λt.RankEx2_ind(t;
                           RankEx2_LeafT(leaft) LeafT[leaft];
                           RankEx2_LeafS(leafs) LeafS[leafs];
                           RankEx2_Prod(prod) rec1.Prod[prod;rec1];
                           RankEx2_Union(union) rec2.Union[union;rec2];
                           RankEx2_ListProd(listprod) rec3.ListProd[listprod;rec3];
                           RankEx2_UnionList(unionlist) rec4.UnionList[unionlist;rec4])  in
        if RankEx2_LeafT?(t) then LeafT RankEx2_LeafT-leaft(t)
        if RankEx2_LeafS?(t) then LeafS RankEx2_LeafS-leafs(t)
        if RankEx2_Prod?(t) then Prod RankEx2_Prod-prod(t) (F (fst(fst(RankEx2_Prod-prod(t)))))
        if RankEx2_Union?(t)
          then Union RankEx2_Union-union(t) 
               case RankEx2_Union-union(t) of inl(x) => let x1,x2 in x2 inr(y) => y
        if RankEx2_ListProd?(t)
          then ListProd RankEx2_ListProd-listprod(t) i.let u2,u3 RankEx2_ListProd-listprod(t)[i] in u3)
        else UnionList RankEx2_UnionList-unionlist(t) 
             case RankEx2_UnionList-unionlist(t) of inl(x) => Ax inr(y) => λi.(F y[i])
        fi )

Lemma: RankEx2-defop
[T,S,P:Type]. ∀[R:P ⟶ RankEx2(S;T) ⟶ ℙ].
  ((∀t:T. (∃x:{P| (R RankEx2_LeafT(t))}))
   (∀s:S. (∃x:{P| (R RankEx2_LeafS(s))}))
   (∀d:RankEx2(S;T). ∀s:S. ∀t:T.  ((∃x:{P| (R d)})  (∃x:{P| (R RankEx2_Prod(<<d, s>t>))})))
   (∀z:S × RankEx2(S;T) RankEx2(S;T)
        (case of inl(p) => ∃x:{P| (R (snd(p)))} inr(d) => ∃x:{P| (R d)}  (∃x:{P| (R RankEx2_Union(z))})))
   (∀L:(S × RankEx2(S;T)) List. ((∀p∈L.∃x:{P| (R (snd(p)))})  (∃x:{P| (R RankEx2_ListProd(L))})))
   (∀z:T (RankEx2(S;T) List)
        (case of inl(p) => True inr(L) => (∀p∈L.∃x:{P| (R p)})  (∃x:{P| (R RankEx2_UnionList(z))})))
   {∀t:RankEx2(S;T). (∃x:{P| (R t)})})

Lemma: RankEx2-defop-extract
[T,S,P:Type]. ∀[R:P ⟶ RankEx2(S;T) ⟶ ℙ].
  ((∀t:T. (∃x:{P| (R RankEx2_LeafT(t))}))
   (∀s:S. (∃x:{P| (R RankEx2_LeafS(s))}))
   (∀d:RankEx2(S;T). ∀s:S. ∀t:T.  ((∃x:{P| (R d)})  (∃x:{P| (R RankEx2_Prod(<<d, s>t>))})))
   (∀z:S × RankEx2(S;T) RankEx2(S;T)
        (case of inl(p) => ∃x:{P| (R (snd(p)))} inr(d) => ∃x:{P| (R d)}  (∃x:{P| (R RankEx2_Union(z))})))
   (∀L:(S × RankEx2(S;T)) List. ((∀p∈L.∃x:{P| (R (snd(p)))})  (∃x:{P| (R RankEx2_ListProd(L))})))
   (∀z:T (RankEx2(S;T) List)
        (case of inl(p) => True inr(L) => (∀p∈L.∃x:{P| (R p)})  (∃x:{P| (R RankEx2_UnionList(z))})))
   {∀t:RankEx2(S;T). (∃x:{P| (R t)})})

Definition: RankEx4co
RankEx4co() ==  corec(X.lbl:Atom × if lbl =a "Foo" then ℤ else Void fi )

Lemma: RankEx4co_wf
RankEx4co() ∈ Type

Lemma: RankEx4co-ext
RankEx4co() ≡ lbl:Atom × if lbl =a "Foo" then ℤ RankEx4co() else Void fi 

Definition: RankEx4co_size
RankEx4co_size(p) ==
  fix((λsize,p. let lbl,x in if lbl =a "Foo" then case of inl(a) => inr(b) => size else fi )) p

Lemma: RankEx4co_size_wf
[p:RankEx4co()]. (RankEx4co_size(p) ∈ partial(ℕ))

Definition: RankEx4
RankEx4() ==  {p:RankEx4co()| (RankEx4co_size(p))↓

Lemma: RankEx4_wf
RankEx4() ∈ Type

Definition: RankEx4_size
RankEx4_size(p) ==
  fix((λsize,p. let lbl,x in if lbl =a "Foo" then case of inl(a) => inr(b) => size else fi )) p

Lemma: RankEx4_size_wf
[p:RankEx4()]. (RankEx4_size(p) ∈ ℕ)

Lemma: RankEx4-ext
RankEx4() ≡ lbl:Atom × if lbl =a "Foo" then ℤ RankEx4() else Void fi 

Definition: RankEx4_Foo
RankEx4_Foo(foo) ==  <"Foo", foo>

Lemma: RankEx4_Foo_wf
[foo:ℤ RankEx4()]. (RankEx4_Foo(foo) ∈ RankEx4())

Definition: RankEx4_Foo?
RankEx4_Foo?(v) ==  fst(v) =a "Foo"

Lemma: RankEx4_Foo?_wf
[v:RankEx4()]. (RankEx4_Foo?(v) ∈ 𝔹)

Definition: RankEx4_Foo-foo
RankEx4_Foo-foo(v) ==  snd(v)

Lemma: RankEx4_Foo-foo_wf
[v:RankEx4()]. RankEx4_Foo-foo(v) ∈ ℤ RankEx4() supposing ↑RankEx4_Foo?(v)

Lemma: RankEx4-induction
[P:RankEx4() ⟶ ℙ]
  ((∀foo:ℤ RankEx4(). (case foo of inl(u) => True inr(u1) => P[u1]  P[RankEx4_Foo(foo)]))  {∀v:RankEx4(). P[v]})

Lemma: RankEx4-definition
[A:Type]. ∀[R:A ⟶ RankEx4() ⟶ ℙ].
  ((∀foo:ℤ RankEx4(). (case foo of inl(u) => True inr(u1) => {x:A| R[x;u1]}   {x:A| R[x;RankEx4_Foo(foo)]} ))
   {∀v:RankEx4(). {x:A| R[x;v]} })

Definition: RankEx4_ind
RankEx4_ind(v;
            RankEx4_Foo(foo) rec1.Foo[foo; rec1])  ==
  fix((λRankEx4_ind,v. let lbl,v1 
                       in if lbl="Foo"
                          then case v1 of inl(x) => Foo[inl x; Ax] inr(y) => Foo[inr RankEx4_ind y]
                          else Ax
                          fi )) 
  v

Lemma: RankEx4_ind_wf
[A:Type]. ∀[R:A ⟶ RankEx4() ⟶ ℙ]. ∀[v:RankEx4()]. ∀[Foo:foo:(ℤ RankEx4())
                                                           ⟶ case foo of inl(u) => True inr(u1) => {x:A| R[x;u1]} 
                                                           ⟶ {x:A| R[x;RankEx4_Foo(foo)]} ].
  (RankEx4_ind(v;
               RankEx4_Foo(foo) rec1.Foo[foo;rec1])  ∈ {x:A| R[x;v]} )

Lemma: RankEx4_ind_wf_simple
[A:Type]. ∀[v:RankEx4()]. ∀[Foo:foo:(ℤ RankEx4()) ⟶ case foo of inl(u) => True inr(u1) => A ⟶ A].
  (RankEx4_ind(v;
               RankEx4_Foo(foo) rec1.Foo[foo;rec1])  ∈ A)

Lemma: UallTest1
F:∀[T:Type]. (T ⟶ T). ∀S:Type. ∀s:S.  ((F s) s ∈ S)

Definition: binary-treeco
binary-treeco() ==  corec(X.lbl:Atom × if lbl =a "Leaf" then ℤ if lbl =a "Node" then left:X × else Void fi )

Lemma: binary-treeco_wf
binary-treeco() ∈ Type

Lemma: binary-treeco-ext
binary-treeco() ≡ lbl:Atom × if lbl =a "Leaf" then ℤ
                             if lbl =a "Node" then left:binary-treeco() × binary-treeco()
                             else Void
                             fi 

Definition: binary-treeco_size
binary-treeco_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Node" then let left,right in (1 (size left)) (size right)
                   else 0
                   fi )) 
  p

Lemma: binary-treeco_size_wf
[p:binary-treeco()]. (binary-treeco_size(p) ∈ partial(ℕ))

Definition: binary-tree
binary-tree() ==  {p:binary-treeco()| (binary-treeco_size(p))↓

Lemma: binary-tree_wf
binary-tree() ∈ Type

Definition: binary-tree_size
binary-tree_size(p) ==
  fix((λsize,p. let lbl,x 
                in if lbl =a "Leaf" then 0
                   if lbl =a "Node" then let left,right in (1 (size left)) (size right)
                   else 0
                   fi )) 
  p

Lemma: binary-tree_size_wf
[p:binary-tree()]. (binary-tree_size(p) ∈ ℕ)

Lemma: binary-tree-ext
binary-tree() ≡ lbl:Atom × if lbl =a "Leaf" then ℤ
                           if lbl =a "Node" then left:binary-tree() × binary-tree()
                           else Void
                           fi 

Definition: btr_Leaf
btr_Leaf(val) ==  <"Leaf", val>

Lemma: btr_Leaf_wf
[val:ℤ]. (btr_Leaf(val) ∈ binary-tree())

Definition: btr_Node
btr_Node(left;right) ==  <"Node", left, right>

Lemma: btr_Node_wf
[left,right:binary-tree()].  (btr_Node(left;right) ∈ binary-tree())

Definition: btr_Leaf?
btr_Leaf?(v) ==  fst(v) =a "Leaf"

Lemma: btr_Leaf?_wf
[v:binary-tree()]. (btr_Leaf?(v) ∈ 𝔹)

Definition: btr_Leaf-val
btr_Leaf-val(v) ==  snd(v)

Lemma: btr_Leaf-val_wf
[v:binary-tree()]. btr_Leaf-val(v) ∈ ℤ supposing ↑btr_Leaf?(v)

Definition: btr_Node?
btr_Node?(v) ==  fst(v) =a "Node"

Lemma: btr_Node?_wf
[v:binary-tree()]. (btr_Node?(v) ∈ 𝔹)

Definition: btr_Node-left
btr_Node-left(v) ==  fst(snd(v))

Lemma: btr_Node-left_wf
[v:binary-tree()]. btr_Node-left(v) ∈ binary-tree() supposing ↑btr_Node?(v)

Definition: btr_Node-right
btr_Node-right(v) ==  snd(snd(v))

Lemma: btr_Node-right_wf
[v:binary-tree()]. btr_Node-right(v) ∈ binary-tree() supposing ↑btr_Node?(v)

Lemma: binary-tree-induction
[P:binary-tree() ⟶ ℙ]
  ((∀val:ℤP[btr_Leaf(val)])
   (∀left,right:binary-tree().  (P[left]  P[right]  P[btr_Node(left;right)]))
   {∀v:binary-tree(). P[v]})

Lemma: binary-tree-definition
[A:Type]. ∀[R:A ⟶ binary-tree() ⟶ ℙ].
  ((∀val:ℤ{x:A| R[x;btr_Leaf(val)]} )
   (∀left,right:binary-tree().  ({x:A| R[x;left]}   {x:A| R[x;right]}   {x:A| R[x;btr_Node(left;right)]} ))
   {∀v:binary-tree(). {x:A| R[x;v]} })

Definition: binary-tree_ind
binary-tree_ind(v;
                btr_Leaf(val) Leaf[val];
                btr_Node(left,right) rec1,rec2.Node[left; right; rec1; rec2])  ==
  fix((λbinary-tree_ind,v. let lbl,v1 
                           in if lbl="Leaf" then Leaf[v1]
                              if lbl="Node"
                                then let left,v2 v1 
                                     in Node[left; v2; binary-tree_ind left; binary-tree_ind v2]
                              else Ax
                              fi )) 
  v

Lemma: binary-tree_ind_wf
[A:Type]. ∀[R:A ⟶ binary-tree() ⟶ ℙ]. ∀[v:binary-tree()]. ∀[Leaf:val:ℤ ⟶ {x:A| R[x;btr_Leaf(val)]} ].
[Node:left:binary-tree()
       ⟶ right:binary-tree()
       ⟶ {x:A| R[x;left]} 
       ⟶ {x:A| R[x;right]} 
       ⟶ {x:A| R[x;btr_Node(left;right)]} ].
  (binary-tree_ind(v;
                   btr_Leaf(val) Leaf[val];
                   btr_Node(left,right) rec1,rec2.Node[left;right;rec1;rec2])  ∈ {x:A| R[x;v]} )

Lemma: binary-tree_ind_wf_simple
[A:Type]. ∀[v:binary-tree()]. ∀[Leaf:val:ℤ ⟶ A]. ∀[Node:left:binary-tree() ⟶ right:binary-tree() ⟶ A ⟶ A ⟶ A].
  (binary-tree_ind(v;
                   btr_Leaf(val) Leaf[val];
                   btr_Node(left,right) rec1,rec2.Node[left;right;rec1;rec2])  ∈ A)



Home Index