Definition: tuple-type
tuple-type(L) ==  rec-case(L) of [] => Unit T::Ts => r.if null(Ts) then else T × fi 

Lemma: tuple-type_wf
[L:Type List]. (tuple-type(L) ∈ Type)

Definition: n-tuple
n-tuple(n) ==  tuple-type(map(λx.Top;upto(n)))

Lemma: n-tuple_wf
[n:ℕ]. (n-tuple(n) ∈ Type)

Lemma: n-tuple-decomp
[n:ℕ]. (n-tuple(n) if (n =z 0) then Unit if (n =z 1) then Top else Top × n-tuple(n 1) fi )

Lemma: tupletype_nil_lemma
tuple-type([]) Unit

Lemma: tupletype_cons_lemma
L,T:Top.  (tuple-type([T L]) if null(L) then else T × tuple-type(L) fi )

Lemma: tuple-type-valueall-type
[L:{T:Type| valueall-type(T)}  List]. valueall-type(tuple-type(L))

Lemma: subtype_rel_tuple-type
[As,Bs:Type List].  tuple-type(As) ⊆tuple-type(Bs) supposing (||As|| ||Bs|| ∈ ℤ) ∧ (∀i:ℕ||As||. (As[i] ⊆Bs[i]))

Lemma: tuple-type-ext
[L,L':Type List].  tuple-type(L) ≡ tuple-type(L') supposing (||L|| ||L'|| ∈ ℤ) ∧ (∀i:ℕ||L||. L[i] ≡ L'[i])

Lemma: tuple-type-subtype-n-tuple
[L:Type List]. ∀[n:ℕ].  tuple-type(L) ⊆n-tuple(n) supposing ||L|| n ∈ ℤ

Definition: tuple
tuple(n;i.F[i]) ==  rec-case(map(λi.F[i];upto(n))) of [] => ⋅ a::as => r.if null(as) then else <a, r> fi 

Lemma: tuple_wf
[L:Type List]. ∀[F:i:ℕ||L|| ⟶ L[i]]. ∀[n:{n:ℤ||L|| ∈ ℤ].  (tuple(n;i.F[i]) ∈ tuple-type(L))

Lemma: tuple-decomp
[n:ℕ]. ∀[F:Top].  (tuple(n;i.F[i]) if (n =z 0) then ⋅ if (n =z 1) then F[0] else <F[0], tuple(n 1;i.F[i 1])> fi )

Lemma: tuple_wf_ntuple
[n:ℕ]. ∀[F:Top].  (tuple(n;i.F[i]) ∈ n-tuple(n))

Lemma: tuple1_lemma
F:Top. (tuple(1;x.F[x]) F[0])

Lemma: tuple2_lemma
F:Top. (tuple(2;x.F[x]) ~ <F[0], F[1]>)

Definition: ap-tuple
ap-tuple(len;f;t) ==
  fix((λap-tuple,len,f,t. if (len =z 0) then t
                         if (len =z 1) then t
                         else <(fst(f)) (fst(t)), ap-tuple (len 1) (snd(f)) (snd(t))>
                         fi )) 
  len 
  
  t

Lemma: ap-tuple_wf
[n:ℕ]. ∀[A,B:Type List].
  ∀[f:tuple-type(map(λp.((fst(p)) ⟶ (snd(p)));zip(A;B)))]. ∀[t:tuple-type(A)].  (ap-tuple(n;f;t) ∈ tuple-type(B)) 
  supposing (||A|| n ∈ ℤ) ∧ (||B|| n ∈ ℤ)

Definition: ap2-tuple
ap2-tuple(len;f;x;t) ==
  fix((λap2-tuple,len,f,t. if (len =z 0) then t
                          if (len =z 1) then t
                          else <(fst(f)) (fst(t)), ap2-tuple (len 1) (snd(f)) (snd(t))>
                          fi )) 
  len 
  
  t

Lemma: ap2-tuple_wf
[n:ℕ]. ∀[A,B:Type List].
  ∀[C:Type]. ∀[x:C]. ∀[f:tuple-type(map(λp.(C ⟶ (fst(p)) ⟶ (snd(p)));zip(A;B)))]. ∀[t:tuple-type(A)].
    (ap2-tuple(n;f;x;t) ∈ tuple-type(B)) 
  supposing (||A|| n ∈ ℤ) ∧ (||B|| n ∈ ℤ)

Lemma: ap2-tuple_wf_ntuple
[n:ℕ]. ∀[x:Top]. ∀[f,t:n-tuple(n)].  (ap2-tuple(n;f;x;t) ∈ n-tuple(n))

Definition: map-tuple
map-tuple(len;f;t) ==
  fix((λmap-tuple,len,t. if (len =z 0) then if (len =z 1) then else <(fst(t)), map-tuple (len 1) (snd(t))> fi \000C)) len t

Lemma: map-tuple_wf
[n:ℕ]. ∀[A,B:Type List].
  ∀[f:⋂i:ℕn. (A[i] ⟶ B[i])]. ∀[t:tuple-type(A)].  (map-tuple(n;f;t) ∈ tuple-type(B)) 
  supposing (||A|| n ∈ ℤ) ∧ (||B|| n ∈ ℤ)

Lemma: map-tuple_wf_ntuple
[n:ℕ]. ∀[f:Top]. ∀[t:n-tuple(n)].  (map-tuple(n;f;t) ∈ n-tuple(n))

Definition: tuple-sum
tuple-sum(f;L;x) ==
  if null(L) then else let a,as in if null(as) then else let u,v in (f u) tuple-sum(f;as;v) fi  fi 

Lemma: tuple-sum_wf
[P:Type]. ∀[as:P List]. ∀[G:P ⟶ Type]. ∀[x:tuple-type(map(G;as))]. ∀[f:i:P ⟶ (G i) ⟶ ℕ].  (tuple-sum(f;as;x) ∈ ℕ)

Lemma: tuple-sum-wf-partial
[P:Type]. ∀[G:P ⟶ Type]. ∀[f:i:P ⟶ (G i) ⟶ partial(ℕ)]. ∀[as:P List]. ∀[x:tuple-type(map(G;as))].
  (tuple-sum(f;as;x) ∈ partial(ℕ))

Definition: update-tuple
update-tuple(len;x;n;y) ==
  fix((λupdate-tuple,len,x,n. if (n =z 0)
                             then if (len =z 1) then else <y, snd(x)> fi 
                             else <fst(x), update-tuple (len 1) (snd(x)) (n 1)>
                             fi )) 
  len 
  
  n

Lemma: update-tuple_wf
[L:Type List]. ∀[n:ℕ]. ∀[x:tuple-type(L)].  ∀[y:L[n]]. (update-tuple(||L||;x;n;y) ∈ tuple-type(L)) supposing n < ||L||

Definition: select-tuple
x.n ==
  fix((λselect-tuple,len,x,n. if (n =z 0)
                             then if (len =z 1) then else fst(x) fi 
                             else select-tuple (len 1) (snd(x)) (n 1)
                             fi )) 
  len 
  
  n

Lemma: select-tuple_wf
[L:Type List]. ∀[n:ℕ]. ∀[k:ℤ].  ∀[x:tuple-type(L)]. (x.n ∈ L[n]) supposing n < ||L|| ∧ (k ||L|| ∈ ℤ)

Lemma: select-tuple-tuple
[n:ℕ]. ∀[i:ℕn]. ∀[F:Top].  (tuple(n;i.F[i]).i F[i])

Lemma: map-tuple-as-tuple
[n:ℕ]. ∀[f:Top]. ∀[t:n-tuple(n)].  (map-tuple(n;f;t) tuple(n;i.f t.i))

Lemma: map-tuple-tuple
[n:ℕ]. ∀[f,G:Top].  (map-tuple(n;f;tuple(n;i.G[i])) tuple(n;i.f G[i]))

Lemma: ap-tuple-as-tuple
[n:ℕ]. ∀[f,t:n-tuple(n)].  (ap-tuple(n;f;t) tuple(n;i.f.i t.i))

Lemma: ap2-tuple-as-tuple
[n:ℕ]. ∀[f,t:n-tuple(n)]. ∀[x:Top].  (ap2-tuple(n;f;x;t) tuple(n;i.f.i t.i))

Lemma: map-tuple-ap2-tuple
[n:ℕ]. ∀[f,x:Top]. ∀[g,t:n-tuple(n)].
  (map-tuple(n;f;ap2-tuple(n;g;x;t)) ap2-tuple(n;map-tuple(n;λh,x,z. (f (h z));g);x;t))

Lemma: le-tuple-sum
[P:Type]. ∀[as:P List]. ∀[G:P ⟶ Type]. ∀[x:tuple-type(map(G;as))]. ∀[f:i:P ⟶ (G i) ⟶ ℕ].
  ∀k:ℕ||as||. ((f as[k] x.k) ≤ tuple-sum(f;as;x))

Definition: split-tuple
split-tuple(x;n) ==
  fix((λsplit-tuple,x,n. if (n =z 0) then <⋅x>
                        if (n =z 1) then <fst(x), snd(x)>
                        else let a,b split-tuple (snd(x)) (n 1) 
                             in <<fst(x), a>b>
                        fi )) 
  
  n

Lemma: split-tuple_wf
[L:Type List]. ∀[x:tuple-type(L)]. ∀[n:ℕ||L||].  (split-tuple(x;n) ∈ tuple-type(firstn(n;L)) × tuple-type(nth_tl(n;L)))

Definition: shorten-tuple
shorten-tuple(x;n) ==  fix((λshorten-tuple,x,n. if n ≤then else shorten-tuple (snd(x)) (n 1) fi )) n

Lemma: shorten-tuple-split-tuple
[n:ℕ]. ∀[x:Top].  (shorten-tuple(x;n) snd(split-tuple(x;n)))

Lemma: shorten-tuple_wf
[L:Type List]. ∀[n:ℕ||L||]. ∀[x:tuple-type(L)].  (shorten-tuple(x;n) ∈ tuple-type(nth_tl(n;L)))

Lemma: shorten-tuple_wf2
[L1,L2:Type List]. ∀[x:tuple-type(L1 L2)].  shorten-tuple(x;||L1||) ∈ tuple-type(L2) supposing 0 < ||L2||

Definition: append-tuple
append-tuple(n;m;x;y) ==
  fix((λappend-tuple,n,x. if n ≤then y
                         if (n =z 1) then if m ≤then else <x, y> fi 
                         else let a,b 
                              in <a, append-tuple (n 1) b>
                         fi )) 
  
  x

Lemma: append-tuple_wf
[L1,L2:Type List]. ∀[x:tuple-type(L1)]. ∀[y:tuple-type(L2)].  (append-tuple(||L1||;||L2||;x;y) ∈ tuple-type(L1 L2))

Lemma: append-tuple-zero
[L:Type List]. ∀[x:tuple-type(L)]. ∀[y:Top].  (append-tuple(||L||;0;x;y) if (||L|| =z 0) then else fi )

Lemma: append-tuple-split-tuple
[L:Type List]. ∀[x:tuple-type(L)]. ∀[n:ℕ||L||].
  (append-tuple(n;||L|| n;fst(split-tuple(x;n));snd(split-tuple(x;n))) x)

Lemma: split-tuple-append-tuple
[L1,L2:Type List].
  ∀[x:tuple-type(L1)]. ∀[y:tuple-type(L2)].  (split-tuple(append-tuple(||L1||;||L2||;x;y);||L1||) ~ <x, y>supposing \000C< ||L2||

Lemma: append-tuple-shorten-tuple
[L:Type List]. ∀[x:tuple-type(L)]. ∀[n:ℕ||L||].
  (append-tuple(n;||L|| n;fst(split-tuple(x;n));shorten-tuple(x;n)) x)

Lemma: append-tuple-simplify
[p:Top × Top]. (fst(snd(let x,y in <x, y, ⋅>)) snd(p))

Lemma: shorten-tuple-simplify
[p:Top × Top × Top]. (fst(shorten-tuple(p;1)) fst(snd(p)))

Lemma: shorten-tuple-simplify2
[p:Top × Top × Top]. (snd(shorten-tuple(p;1)) snd(snd(p)))

Lemma: append-tuple-simplify2
[p:Top × Top]. (fst(let x,y in <x, y, ⋅>fst(p))

Lemma: append-tuple-one-one
[L1,L2:Type List].
  ∀[x1,x2:tuple-type(L1)]. ∀[y1,y2:tuple-type(L2)].
    {(x1 x2 ∈ tuple-type(L1)) ∧ (y1 y2 ∈ tuple-type(L2))} 
    supposing append-tuple(||L1||;||L2||;x1;y1) append-tuple(||L1||;||L2||;x2;y2) ∈ tuple-type(L1 L2) 
  supposing 0 < ||L2||

Lemma: shorten-tuple-append-tuple
[L1,L2:Type List].
  ∀[x:tuple-type(L1)]. ∀[y:tuple-type(L2)].
    (shorten-tuple(append-tuple(||L1||;||L2||;x;y);||L1||) y ∈ tuple-type(L2)) 
  supposing 0 < ||L2||

Lemma: select-update-tuple
[m,n:ℕ]. ∀[L:Type List].
  (∀[x:tuple-type(L)]. ∀[y:Top].  (update-tuple(||L||;x;n;y).m if (n =z m) then else x.m fi )) supposing 
     (m < ||L|| and 
     n < ||L||)

Lemma: select-shorten-tuple
[n,m:ℕ]. ∀[L:Type List].  ∀[x:tuple-type(L)]. (shorten-tuple(x;n).m x.n m) supposing m < ||L||

Definition: ptuple
ptuple(lbl,p.a[lbl; p];X) ==
  λparam.(labl:{lbl:Atom| 0 < ||a[lbl; param]||}  × tuple-type(map(λx.case x
                                                                of inl(y) =>
                                                                case of inl(p) => inr(p) => (X p) List
                                                                inr(E) =>
                                                                E;a[labl; param])))

Lemma: ptuple_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[X:P ⟶ Type].  (ptuple(lbl,p.a[lbl;p];X) ∈ P ⟶ Type)

Lemma: tuple-type-continuous
[P:Type]. ∀[X:ℕ ⟶ P ⟶ Type]. ∀[L:P List].  ((⋂n:ℕtuple-type(map(X n;L))) ⊆tuple-type(map(λp.⋂n:ℕ(X p);L)))

Lemma: tuple-type-monotone
[P:Type]. ∀[F,G:P ⟶ Type].  ∀[v:P List]. (tuple-type(map(F;v)) ⊆tuple-type(map(G;v))) supposing F ⊆ G

Lemma: ptuple-continuous
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].  type-family-continuous{i:l}(P;λX.ptuple(lbl,p.a[lbl;p];X))

Lemma: ptuple-monotone
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].  family-monotone{i:l}(P;λX.ptuple(lbl,p.a[lbl;p];X))

Definition: pcorec
pcorec(lbl,p.a[lbl; p]) ==  corec-family(λX.ptuple(lbl,p.a[lbl; p];X))

Lemma: pcorec_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].  (pcorec(lbl,p.a[lbl;p]) ∈ P ⟶ Type)

Lemma: pcorec-ext
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].
  pcorec(lbl,p.a[lbl;p]) ≡ ptuple(lbl,p.a[lbl;p];pcorec(lbl,p.a[lbl;p]))

Lemma: fix_wf-pcorec-partial-nat
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[f:⋂X:P ⟶ Type
                                                          ((i:P ⟶ (X i) ⟶ partial(ℕ))
                                                          ⟶ i:P
                                                          ⟶ (ptuple(lbl,p.a[lbl;p];X) i)
                                                          ⟶ partial(ℕ))].
  (fix(f) ∈ i:P ⟶ (pcorec(lbl,p.a[lbl;p]) i) ⟶ partial(ℕ))

Definition: add-sz
add-sz(sz;L;x) ==
  tuple-sum(λc,u. case of inl(z) => case of inl(p) => sz inr(p) => l_sum(map(sz p;u)) inr(E) => 0;L;x)

Lemma: add-sz_wf
[P:Type]. ∀[X:P ⟶ Type]. ∀[sz:i:P ⟶ (X i) ⟶ partial(ℕ)]. ∀[L:(P Type) List].
[x:tuple-type(map(λx.case of inl(y) => case of inl(p) => inr(p) => (X p) List inr(E) => E;L))].
  (add-sz(sz;L;x) ∈ partial(ℕ))

Definition: pcorec-size
pcorec-size(lbl,p.a[lbl; p]) ==  fix((λsz,p,x. let lbl,z in add-sz(sz;a[lbl; p];z)))

Lemma: pcorec-size_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].
  (pcorec-size(lbl,p.a[lbl;p]) ∈ i:P ⟶ (pcorec(lbl,p.a[lbl;p]) i) ⟶ partial(ℕ))

Lemma: unroll-pcorec-size
[a:Top]. (pcorec-size(lbl,p.a[lbl;p]) ~ λp,x. let lbl,z in add-sz(pcorec-size(lbl,p.a[lbl;p]);a[lbl;p];z))

Definition: prec
prec(lbl,p.a[lbl; p];i) ==  {x:pcorec(lbl,p.a[lbl; p]) i| (pcorec-size(lbl,p.a[lbl; p]) x)↓

Lemma: prec_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P].  (prec(lbl,p.a[lbl;p];i) ∈ Type)

Lemma: prec-ext
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P].
  prec(lbl,p.a[lbl;p];i) ≡ labl:{lbl:Atom| 0 < ||a[lbl;i]||}  × tuple-type(map(λx.case x
                                                    of inl(y) =>
                                                    case y
                                                     of inl(p) =>
                                                     prec(lbl,p.a[lbl;p];p)
                                                     inr(p) =>
                                                     prec(lbl,p.a[lbl;p];p) List
                                                    inr(E) =>
                                                    E;a[labl;i]))

Definition: prec-size
||i;x|| ==  pcorec-size(lbl,p.a[lbl; p]) x

Lemma: prec-size_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].  (||i;x|| ∈ ℕ)

Lemma: prec-size-induction
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[Q:i:P ⟶ prec(lbl,p.a[lbl;p];i) ⟶ TYPE].
  ((∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  ((∀j:P. ∀z:{z:prec(lbl,p.a[lbl;p];j)| ||j;z|| < ||i;x||} .  Q[j;z])  Q[i;x]))
   (∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  Q[i;x]))

Lemma: prec-size-induction-ext
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[Q:i:P ⟶ prec(lbl,p.a[lbl;p];i) ⟶ TYPE].
  ((∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  ((∀j:P. ∀z:{z:prec(lbl,p.a[lbl;p];j)| ||j;z|| < ||i;x||} .  Q[j;z])  Q[i;x]))
   (∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  Q[i;x]))

Lemma: unroll-prec-size
[a,i,x:Top].  (||i;x|| let lbl,z in add-sz(pcorec-size(lbl,p.a[lbl;p]);a[lbl;i];z))

Lemma: prec-size-unfold
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].
  (||i;x||
  let lbl,z 
    in 1
       tuple-sum(λc,x. case c
                         of inl(p) =>
                         case of inl(j) => ||j;x|| inr(j) => l_sum(map(λz.||j;z||;x))
                         inr(_) =>
                         0;a[lbl;i];z)
  ∈ ℤ)

Definition: prec-arg-types
prec-arg-types(lbl,p.a[lbl; p];i;lbl) ==
  map(λx.case x
          of inl(y) =>
          case of inl(p) => prec(lbl,p.a[lbl; p];p) inr(p) => prec(lbl,p.a[lbl; p];p) List
          inr(E) =>
          E;a[lbl; i])

Lemma: prec-arg-types_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[lbl:Atom].
  (prec-arg-types(lbl,p.a[lbl;p];i;lbl) ∈ Type List)

Definition: mk-prec
mk-prec(lbl;x) ==  <lbl, x>

Lemma: mk-prec_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[labl:{lbl:Atom| 0 < ||a[lbl;i]||} ].
[x:tuple-type(prec-arg-types(lbl,p.a[lbl;p];i;labl))].
  (mk-prec(labl;x) ∈ prec(lbl,p.a[lbl;p];i))

Definition: dest-prec
dest-prec(x) ==  x

Lemma: dest-prec_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].
  (dest-prec(x) ∈ lbl:{lbl:Atom| 0 < ||a[lbl;i]||}  × tuple-type(prec-arg-types(lbl,p.a[lbl;p];i;lbl)))

Lemma: dest_mk_prec_lemma
x,lbl:Top.  (dest-prec(mk-prec(lbl;x)) ~ <lbl, x>)

Definition: prec-label
prec-label(x) ==  fst(x)

Lemma: prec-label_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].
  (prec-label(x) ∈ {lbl:Atom| 0 < ||a[lbl;i]||} )

Definition: prec-tuple
prec-tuple(x) ==  snd(x)

Lemma: prec-tuple_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].
  (prec-tuple(x) ∈ tuple-type(prec-arg-types(lbl,p.a[lbl;p];i;prec-label(x))))

Lemma: prec-sq
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[i:P]. ∀[x:prec(lbl,p.a[lbl;p];i)].
  (x mk-prec(prec-label(x);prec-tuple(x)))

Definition: prec-sub
prec-sub(P;lbl,p.a[lbl; p];j;x;i;y) ==
  let lbl,z dest-prec(y) 
  in let a[lbl; i] in
      let ||L|| in
      ∃k:ℕn
       ((↑isl(L[k]))
       ∧ (((outl(L[k]) (inl j) ∈ (P P)) ∧ (x z.k ∈ prec(lbl,i.a[lbl; i];j)))
         ∨ ((outl(L[k]) (inr ) ∈ (P P)) ∧ (x ∈ z.k))))

Lemma: prec-sub_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[j:P]. ∀[x:prec(lbl,p.a[lbl;p];j)]. ∀[i:P].
[y:prec(lbl,p.a[lbl;p];i)].
  (prec-sub(P;lbl,p.a[lbl;p];j;x;i;y) ∈ ℙ)

Lemma: prec-sub-size
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[j:P]. ∀[x:prec(lbl,p.a[lbl;p];j)]. ∀[i:P].
[y:prec(lbl,p.a[lbl;p];i)].
  ||j;x|| < ||i;y|| supposing prec-sub(P;lbl,p.a[lbl;p];j;x;i;y)

Definition: prec_sub
prec_sub(P;lbl,p.a[lbl; p]) ==  λu,v. let j,x in let i,y in prec-sub(P;lbl,p.a[lbl; p];j;x;i;y)

Lemma: prec_sub_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].
  (prec_sub(P;lbl,p.a[lbl;p]) ∈ (i:P × prec(lbl,p.a[lbl;p];i)) ⟶ (i:P × prec(lbl,p.a[lbl;p];i)) ⟶ ℙ)

Definition: prec_sub+
prec_sub+(P;lbl,p.a[lbl; p]) ==  prec_sub(P;lbl,p.a[lbl; p])+

Lemma: prec_sub+_wf
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)].
  (prec_sub+(P;lbl,p.a[lbl;p]) ∈ (i:P × prec(lbl,p.a[lbl;p];i)) ⟶ (i:P × prec(lbl,p.a[lbl;p];i)) ⟶ ℙ)

Lemma: prec-sub+-size
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[j:P]. ∀[x:prec(lbl,p.a[lbl;p];j)]. ∀[i:P].
[y:prec(lbl,p.a[lbl;p];i)].
  ||j;x|| < ||i;y|| supposing prec_sub+(P;lbl,p.a[lbl;p]) <j, x> <i, y>

Lemma: prec-induction
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[Q:i:P ⟶ prec(lbl,p.a[lbl;p];i) ⟶ TYPE].
  ((∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  ((∀j:P. ∀z:{z:prec(lbl,p.a[lbl;p];j)| prec_sub+(P;lbl,p.a[lbl;p]) <j, z> <i, x>.\000C  Q[j;z])  Q[i;x]))
   (∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  Q[i;x]))

Lemma: prec-induction-ext
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[Q:i:P ⟶ prec(lbl,p.a[lbl;p];i) ⟶ TYPE].
  ((∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  ((∀j:P. ∀z:{z:prec(lbl,p.a[lbl;p];j)| prec_sub+(P;lbl,p.a[lbl;p]) <j, z> <i, x>.\000C  Q[j;z])  Q[i;x]))
   (∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  Q[i;x]))

Lemma: prec-definition
[P:Type]. ∀[a:Atom ⟶ P ⟶ ((P Type) List)]. ∀[A:P ⟶ Type]. ∀[R:i:P ⟶ prec(lbl,p.a[lbl;p];i) ⟶ A[i] ⟶ ℙ].
  ((∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).
      ((∀j:P. ∀z:{z:prec(lbl,p.a[lbl;p];j)| prec_sub+(P;lbl,p.a[lbl;p]) <j, z> <i, x>.  (∃a:A[j] [R[j;z;a]]))  (∃a:A\000C[i] [R[i;x;a]])))
   (∀i:P. ∀x:prec(lbl,p.a[lbl;p];i).  (∃a:A[i] [R[i;x;a]])))

Definition: mrec_spec
MutualRectypeSpec ==  (Atom × ((Atom × ((Atom Atom Type) List)) List)) List

Lemma: mrec_spec_wf
MutualRectypeSpec ∈ 𝕌'

Definition: mrec-spec
mrec-spec(L;lbl;p) ==
  case apply-alist(AtomDeq;L;p)
   of inl(L2) =>
   case apply-alist(AtomDeq;L2;lbl) of inl(as) => as inr(_) => []
   inr(_) =>
   []

Lemma: mrec-spec_wf
[L:MutualRectypeSpec]. ∀[lbl,p:Atom].  (mrec-spec(L;lbl;p) ∈ (Atom Atom Type) List)

Definition: mrec
mrec(L;i) ==  prec(lbl,p.mrec-spec(L;lbl;p);i)

Lemma: mrec_wf
[L:MutualRectypeSpec]. ∀[i:Atom].  (mrec(L;i) ∈ Type)

Definition: mkinds
mKinds ==  {a:Atom| (a ∈ eager-map(λp.(fst(p));L))} 

Lemma: mkinds_wf
[L:MutualRectypeSpec]. (mKinds ∈ Type)

Definition: mtype
mtype(L;i) ==  apply_alist(AtomDeq;eager-map(λp.let i,x in <i, mrec(L;i)>;L);i)

Lemma: mtype-sqequal
[L:MutualRectypeSpec]. ∀[i:mKinds].  (mtype(L;i) mrec(L;i))

Lemma: mtype_wf
[L:MutualRectypeSpec]. ∀[i:mKinds].  (mtype(L;i) ∈ Type)

Lemma: mrec-label-cases
s:MutualRectypeSpec. ∀n:Atom. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(s;lbl;n)||} .
  ((↑isl(apply-alist(AtomDeq;s;n))) ∧ (lbl ∈ map(λp.(fst(p));outl(apply-alist(AtomDeq;s;n)))))

Lemma: mrec-label-cases1
s:MutualRectypeSpec. ∀n:Atom. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(s;lbl;n)||} .
  (lbl ∈ eager-map(λp.(fst(p));outl(apply-alist(AtomDeq;s;n))))

Definition: mrec-member
mrec-member(s;n;lbl) ==
  case rec-case(map(λp.(fst(p));outl(rec-case(s) of
                                     [] => inr Ax 
                                     p::ps =>
                                      r.if fst(p) =a then inl (snd(p)) else fi ))) of
       [] => inr _.Ax) 
       a::L =>
        r.case r
        of inl(z) =>
        if lbl=a then inl <0, Ax, Ax> else inl let i,_,_ in <1, Ax, Ax> fi 
        inr(_) =>
        if lbl=a then inl <0, Ax, Ax> else inr _.Ax)  fi 
   of inl(x) =>
   x
   inr(_) =>
   Ax

Lemma: mrec-label-cases1-ext
s:MutualRectypeSpec. ∀n:Atom. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(s;lbl;n)||} .
  (lbl ∈ eager-map(λp.(fst(p));outl(apply-alist(AtomDeq;s;n))))

Lemma: mrec-label-cases2
s:MutualRectypeSpec. ∀n:Atom. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(s;lbl;n)||} .  (n ∈ eager-map(λp.(fst(p));s))

Definition: mobj
mobj(L) ==  i:mKinds × mtype(L;i)

Lemma: mobj_wf
[L:MutualRectypeSpec]. (mobj(L) ∈ Type)

Definition: mobj-kind
mobj-kind(x) ==  fst(x)

Lemma: mobj-kind_wf
[s:MutualRectypeSpec]. ∀[x:mobj(s)].  (mobj-kind(x) ∈ mKinds)

Definition: mobj-data
mobj-data(x) ==  snd(x)

Lemma: mobj-data_wf
[s:MutualRectypeSpec]. ∀[x:mobj(s)].  (mobj-data(x) ∈ mtype(s;mobj-kind(x)))

Lemma: mobj-ext
[L:MutualRectypeSpec]. mobj(L) ≡ i:Atom × mrec(L;i)

Definition: mobj-label
mobj-label(x) ==  prec-label(mobj-data(x))

Lemma: mobj-label_wf
[S:MutualRectypeSpec]. ∀[x:mobj(S)].  (mobj-label(x) ∈ {lbl:Atom| 0 < ||mrec-spec(S;lbl;mobj-kind(x))||} )

Definition: mobj-tuple
mobj-tuple(x) ==  prec-tuple(mobj-data(x))

Lemma: mobj-tuple_wf
[S:MutualRectypeSpec]. ∀[x:mobj(S)].
  (mobj-tuple(x) ∈ tuple-type(prec-arg-types(lbl,p.mrec-spec(S;lbl;p);mobj-kind(x);mobj-label(x))))

Lemma: mobj-sq
[S:MutualRectypeSpec]. ∀[x:mobj(S)].  (x ~ <mobj-kind(x), mk-prec(mobj-label(x);mobj-tuple(x))>)

Lemma: mobj-cases
[S:MutualRectypeSpec]. ∀[P:mobj(S) ⟶ TYPE].
  ((∀k:mKinds. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(S;lbl;k)||} .
    ∀t:tuple-type(prec-arg-types(lbl,p.mrec-spec(S;lbl;p);k;lbl)).
      P[<k, mk-prec(lbl;t)>])
   (∀x:mobj(S). P[x]))

Definition: mrec-lt
x < ==  prec_sub+(Atom;lbl,p.mrec-spec(L;lbl;p)) y

Lemma: mrec-lt_wf
[L:MutualRectypeSpec]. ∀[x,y:mobj(L)].  (x < y ∈ ℙ)

Lemma: mrec-lt_transitivity
[L:MutualRectypeSpec]. ∀[x,y,z:mobj(L)].  (x <  y <  x < z)

Lemma: implies-mrec-lt
[L:MutualRectypeSpec]. ∀[x:mobj(L)].  ∀y:mobj(L). ((prec_sub(Atom;lbl,p.mrec-spec(L;lbl;p)) y)  x < y)

Lemma: mrec-induction
[L:MutualRectypeSpec]. ∀[P:mobj(L) ⟶ TYPE].
  ((∀x:mobj(L). ((∀z:{z:mobj(L)| z < x} P[z])  P[x]))  (∀x:mobj(L). P[x]))

Definition: mrecind
mrecind(L;x.P[x]) ==
  ∀k:mKinds. ∀lbl:{lbl:Atom| 0 < ||mrec-spec(L;lbl;k)||} . ∀t:tuple-type(prec-arg-types(lbl,p.mrec-spec(L;lbl;p);k;lbl))\000C.
    ((∀j:ℕ||mrec-spec(L;lbl;k)||
        case mrec-spec(L;lbl;k)[j] of inl(y) => case of inl(p) => P[<p, t.j>inr(p) => (∀u∈t.j.P[<p, u>]) inr(_) \000C=> True)
     P[<k, mk-prec(lbl;t)>])

Lemma: mrecind_wf
[L:MutualRectypeSpec]. ∀[P:mobj(L) ⟶ ℙ].  (mrecind(L;x.P[x]) ∈ ℙ)

Lemma: istype-mrecind
[L:MutualRectypeSpec]. ∀[P:mobj(L) ⟶ TYPE].  istype(mrecind(L;x.P[x]))

Lemma: mrec-induction2
L:MutualRectypeSpec. ∀[P:mobj(L) ⟶ TYPE]. (mrecind(L;x.P[x])  (∀x:mobj(L). P[x]))

Lemma: mrec-induction2-ext
L:MutualRectypeSpec. ∀[P:mobj(L) ⟶ TYPE]. (mrecind(L;x.P[x])  (∀x:mobj(L). P[x]))

Definition: mrec_ind
mrec_ind(L;h;x) ==
  let i,x1 
  in letrec r(i)=λx.(h (fst(x)) (snd(x)) 
                     let L' case apply-alist(AtomDeq;L;i)
                               of inl(L2) =>
                               case apply-alist(AtomDeq;L2;fst(x)) of inl(as) => as inr(_) => Ax
                               inr(_) =>
                               Ax in
                         λj.case L'[j]
                             of inl(x@0) =>
                             case x@0 of inl(x1) => x1 snd(x).j inr(y) => λi@0.(r snd(x).j[i@0])
                             inr(y) =>
                             Ax) in
      r(i) 
     x1

Lemma: mrec_ind_wf
L:MutualRectypeSpec. ∀[P:mobj(L) ⟶ TYPE]. ∀[h:mrecind(L;x.P[x])]. ∀[x:mobj(L)].  (mrec_ind(L;h;x) ∈ P[x])

Definition: mrec-ind
mrec-ind(h;o) ==  let lbl,tpl in letrec r(i)=λx.(h <i, x> o'.let j,z o' in z)) in r(lbl) tpl

Lemma: mrec-ind_wf
[L:MutualRectypeSpec]. ∀[A:mobj(L) ⟶ TYPE]. ∀[h:x:mobj(L) ⟶ (z:{z:mobj(L)| z < x}  ⟶ A[z]) ⟶ A[x]]. ∀[o:mobj(L)].
  (mrec-ind(h;o) ∈ A[o])

Lemma: mk-prec_wf-mrec
[L:MutualRectypeSpec]. ∀[i,labl:Atom]. ∀[x:tuple-type(prec-arg-types(lbl,p.mrec-spec(L;lbl;p);i;labl))].
  mk-prec(labl;x) ∈ mrec(L;i) supposing 0 < ||mrec-spec(L;labl;i)||

Definition: tuple-equiv
tuple-equiv(L) ==  λt,t'. let ||L|| in ∀i:ℕn. ((snd(L[i])) t.i t'.i)

Lemma: tuple-equiv_wf
[L:(X:Type × (X ⟶ X ⟶ ℙ)) List]
  (tuple-equiv(L) ∈ tuple-type(map(λp.(fst(p));L)) ⟶ tuple-type(map(λp.(fst(p));L)) ⟶ ℙ)

Lemma: tuple-equiv-is-equiv
L:(X:Type × (X ⟶ X ⟶ ℙ)) List
  ((∀i:ℕ||L||. let X,E L[i] in EquivRel(X;x,y.E y))
   EquivRel(tuple-type(map(λp.(fst(p));L));t,t'.tuple-equiv(L) t'))



Home Index