Definition: varname
varname() ==  Atom ⋃ (Atom × ℕ)

Lemma: varname_wf
varname() ∈ Type

Definition: num-var
t_n ==  <t, n>

Lemma: num-var_wf
[t:Atom]. ∀[n:ℕ].  (t_n ∈ varname())

Definition: eq_var
eq_var(a;b) ==
  if is an atom then if is an atom then =a otherwise ff otherwise let x,n 
                                                                          in if is an atom then ff
                                                                             otherwise let y,m 
                                                                                       in =a y ∧b (n =z m)

Lemma: eq_var_wf
[a,b:varname()].  (eq_var(a;b) ∈ 𝔹)

Lemma: assert-eq_var
a,b:varname().  uiff(↑eq_var(a;b);a b ∈ varname())

Definition: var-deq
VarDeq ==  λa,b. eq_var(a;b)

Lemma: var-deq_wf
VarDeq ∈ EqDecider(varname())

Definition: same-binding
same-binding(vs;ws;v;w) ==
  if vs is pair then if ws is pair then let a,as vs 
                                            in let b,bs ws 
                                               in case eq_var(a;v)
                                                   of inl(_) =>
                                                   eq_var(b;w)
                                                   inr(_) =>
                                                   beq_var(b;w)) ∧b same-binding(as;bs;v;w) otherwise ff
  otherwise if ws is pair then ff otherwise eq_var(v;w)

Lemma: same-binding_wf
[vs,ws:varname() List]. ∀[v,w:varname()].  (same-binding(vs;ws;v;w) ∈ 𝔹)

Lemma: same-binding-not-bound
[vs,ws:varname() List].
  ∀v,w:varname().
    ((↑same-binding(vs;ws;v;w))  (v ∈ vs))  {(¬(w ∈ ws)) ∧ (w v ∈ varname()) ∧ (||vs|| ||ws|| ∈ ℤ)})

Lemma: same-binding-refl
[vs:varname() List]. ∀[v:varname()].  (same-binding(vs;vs;v;v) tt)

Lemma: same-binding-symm
[vs,ws:varname() List]. ∀[v,w:varname()].  (same-binding(vs;ws;v;w) same-binding(ws;vs;w;v))

Lemma: same-binding-trans
[vs,ws,us:varname() List]. ∀[v,w,u:varname()].
  ((↑same-binding(vs;ws;v;w))  (↑same-binding(ws;us;w;u))  (↑same-binding(vs;us;v;u)))

Lemma: atom_subtype_varname
Atom ⊆varname()

Lemma: atomxnat_subtype_varname
(Atom × ℕ) ⊆varname()

Definition: var-num
var-num(t;b) ==
  if is an atom then if =a then else -1 fi  otherwise let x,n 
                                                              in if =a then else -1 fi 

Lemma: var-num_wf
[t:Atom]. ∀[b:varname()].  (var-num(t;b) ∈ {-1...})

Definition: maybe_new_var
maybe_new_var(v;vs) ==
  if null(vs)
  then v
  else eval if is an atom then otherwise fst(v) in
       let n,x list-max(b.var-num(t;b);vs) 
       in if n <then else <t, n> fi 
  fi 

Lemma: maybe_new_var_wf
[v:varname()]. ∀[vs:varname() List].  (maybe_new_var(v;vs) ∈ varname())

Lemma: maybe_new_var-distinct
[a:varname()]. ∀[vs:varname() List].  (∀v∈vs.¬(maybe_new_var(a;vs) v ∈ varname()))

Definition: nullvar
nullvar() ==  ""

Lemma: nullvar_wf
nullvar() ∈ varname()

Lemma: maybe_new_var-is-null
a:varname(). ∀[vs:varname() List]. nullvar() ∈ varname() supposing maybe_new_var(a;vs) nullvar() ∈ varname()

Definition: coterm-fun
coterm-fun(opr;T) ==  {v:varname()| ¬(v nullvar() ∈ varname())}  (opr × ((varname() List × T) List))

Lemma: coterm-fun_wf
[opr,T:Type].  (coterm-fun(opr;T) ∈ Type)

Lemma: coterm-fun-continous
[opr:Type]. ContinuousMonotone(T.coterm-fun(opr;T))

Definition: coterm
coterm(opr) ==  corec(T.coterm-fun(opr;T))

Lemma: coterm_wf
[opr:Type]. (coterm(opr) ∈ Type)

Lemma: coterm-ext
[opr:Type]. coterm(opr) ≡ coterm-fun(opr;coterm(opr))

Definition: coterm-size
coterm-size(t) ==  fix((λsz,t. case of inl(v) => inr(p) => let opr,bts in + Σ(sz (snd(bt)) bt ∈ bts))) t

Lemma: coterm-size_wf
[opr:Type]. ∀[t:coterm(opr)].  (coterm-size(t) ∈ partial(ℕ))

Definition: term
term(opr) ==  {t:coterm(opr)| (coterm-size(t))↓

Lemma: term_wf
[opr:Type]. (term(opr) ∈ Type)

Lemma: term-ext
[opr:Type]. term(opr) ≡ coterm-fun(opr;term(opr))

Definition: isvarterm
isvarterm(t) ==  isl(t)

Lemma: isvarterm_wf
[opr:Type]. ∀[t:term(opr)].  (isvarterm(t) ∈ 𝔹)

Definition: varterm
varterm(v) ==  inl v

Lemma: varterm_wf
[opr:Type]. ∀[v:varname()].  varterm(v) ∈ term(opr) supposing ¬(v nullvar() ∈ varname())

Definition: mkterm
mkterm(opr;bts) ==  inr <opr, bts> 

Lemma: mkterm_wf
[Op:Type]. ∀[opr:Op]. ∀[bts:(varname() List × term(Op)) List].  (mkterm(opr;bts) ∈ term(Op))

Lemma: mkterm-one-one
[Op:Type]. ∀[f,g:Op]. ∀[as,bs:(varname() List × term(Op)) List].
  ((mkterm(f;as) mkterm(g;bs) ∈ term(Op))  {(f g ∈ Op) ∧ (as bs ∈ ((varname() List × term(Op)) List))})

Lemma: assert-isvarterm
[opr:Type]
  ∀t:term(opr). (↑isvarterm(t) ⇐⇒ ∃v:{v:varname()| ¬(v nullvar() ∈ varname())} (t varterm(v) ∈ term(opr)))

Definition: term-size
term-size(t) ==  coterm-size(t)

Lemma: term-size_wf
[opr:Type]. ∀[t:term(opr)].  (term-size(t) ∈ ℕ)

Lemma: term_size_var_lemma
v:Top. (term-size(varterm(v)) 1)

Lemma: term_size_mkterm_lemma
bts,opr:Top.  (term-size(mkterm(opr;bts)) + Σ(term-size(snd(bt)) bt ∈ bts))

Definition: bound-term
bound-term(opr) ==  varname() List × term(opr)

Lemma: bound-term_wf
[opr:Type]. (bound-term(opr) ∈ Type)

Lemma: assert-not-isvarterm
[opr:Type]. ∀t:term(opr). (¬↑isvarterm(t) ⇐⇒ ∃f:opr. ∃bts:bound-term(opr) List. (t mkterm(f;bts) ∈ term(opr)))

Definition: term-opr
term-opr(t) ==  fst(outr(t))

Lemma: term-opr_wf
[opr:Type]. ∀[t:term(opr)].  term-opr(t) ∈ opr supposing ¬↑isvarterm(t)

Definition: term-bts
term-bts(t) ==  snd(outr(t))

Lemma: term-bts_wf
[opr:Type]. ∀[t:term(opr)].  term-bts(t) ∈ bound-term(opr) List supposing ¬↑isvarterm(t)

Lemma: not-isvarterm-implies
[opr:Type]. ∀t:term(opr). ((¬↑isvarterm(t))  (t mkterm(term-opr(t);term-bts(t)) ∈ term(opr)))

Definition: bound-term-size
bound-term-size(bt) ==  term-size(snd(bt))

Lemma: bound-term-size_wf
[opr:Type]. ∀[bt:bound-term(opr)].  (bound-term-size(bt) ∈ ℕ)

Lemma: term-cases
[opr:Type]
  ∀t:term(opr)
    ((∃v:varname(). ((¬(v nullvar() ∈ varname())) ∧ (t varterm(v) ∈ term(opr))))
    ∨ (∃f:opr. ∃bts:{bt:bound-term(opr)| bound-term-size(bt) < term-size(t)}  List. (t mkterm(f;bts) ∈ term(opr))))

Lemma: term-size-positive
[opr:Type]. ∀t:term(opr). (1 ≤ term-size(t))

Definition: immediate-subterm
s < ==
  ∃f:opr. ∃bts:bound-term(opr) List. ((t mkterm(f;bts) ∈ term(opr)) ∧ (∃i:ℕ||bts||. (s (snd(bts[i])) ∈ term(opr))))

Lemma: immediate-subterm_wf
[opr:Type]. ∀[s,t:term(opr)].  (s < t ∈ ℙ)

Lemma: immediate-subterm-size
[opr:Type]. ∀[s,t:term(opr)].  (s <  term-size(s) < term-size(t))

Definition: subterm-rel
subterm-rel(opr) ==  TC(λs,t. s < t)

Lemma: subterm-rel_wf
[opr:Type]. (subterm-rel(opr) ∈ term(opr) ⟶ term(opr) ⟶ ℙ)

Definition: subterm
s << ==  subterm-rel(opr) t

Lemma: subterm_wf
[opr:Type]. ∀[s,t:term(opr)].  (s << t ∈ ℙ)

Lemma: subterm_transitivity
[opr:Type]. ∀s,t,r:term(opr).  (s <<  t <<  s << r)

Lemma: immediate-is-subterm
[opr:Type]. ∀s,t:term(opr).  (s <  s << t)

Lemma: subterm-cases
[opr:Type]. ∀s,t:term(opr).  (s << ⇐⇒ s < t ∨ (∃r:term(opr). (s < r ∧ r << t)))

Lemma: subterm-size
[opr:Type]. ∀[s,t:term(opr)].  (s <<  term-size(s) < term-size(t))

Lemma: subterm-varterm
[opr:Type]. ∀[s:term(opr)]. ∀[v:{v:varname()| ¬(v nullvar() ∈ varname())} ].  s << varterm(v))

Lemma: trivial-subterm
[opr:Type]. ∀f:opr. ∀bts:bound-term(opr) List. ∀i:ℕ||bts||.  snd(bts[i]) << mkterm(f;bts)

Lemma: subterm-mkterm
[opr:Type]
  ∀s:term(opr). ∀f:opr. ∀bts:bound-term(opr) List.
    (s << mkterm(f;bts) ⇐⇒ ∃i:ℕ||bts||. ((s (snd(bts[i])) ∈ term(opr)) ∨ s << snd(bts[i])))

Lemma: bound-term-induction
[opr:Type]. ∀[P:bound-term(opr) ⟶ ℙ].
  ((∀vs:varname() List. ∀v:varname().  ((¬(v nullvar() ∈ varname()))  P[<vs, varterm(v)>]))
   (∀bts:bound-term(opr) List
        ((∀bt:bound-term(opr). ((bt ∈ bts)  P[bt]))  (∀f:opr. ∀vs:varname() List.  P[<vs, mkterm(f;bts)>])))
   (∀bt:bound-term(opr). P[bt]))

Lemma: term-induction1
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].
  ((∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)])
   (∀f:opr. ∀bts:bound-term(opr) List.  ((∀i:ℕ||bts||. P[snd(bts[i])])  P[mkterm(f;bts)]))
   {∀t:term(opr). P[t]})

Definition: term-ind
term-ind(x.varcase[x];f,bts,r.mktermcase[f;
                                         bts;
                                         r];t) ==
  letrec P(a)=case a
   of inl(x) =>
   varcase[x]
   inr(p) =>
   let f,bts 
   in mktermcase[f;
                 bts;
                 λi.(P (snd(bts[i])))] in
   P(t)

Lemma: term-induction1-ext
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].
  ((∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)])
   (∀f:opr. ∀bts:bound-term(opr) List.  ((∀i:ℕ||bts||. P[snd(bts[i])])  P[mkterm(f;bts)]))
   {∀t:term(opr). P[t]})

Lemma: term-ind_wf
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[varcase:∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)]].
[mktermcase:∀f:opr. ∀bts:bound-term(opr) List.  ((∀i:ℕ||bts||. P[snd(bts[i])])  P[mkterm(f;bts)])]. ∀[t:term(opr)].
  (term-ind(x.varcase[x];f,bts,r.mktermcase[f;bts;r];t) ∈ P[t])

Lemma: term-induction
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].
  ((∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)])
   (∀bts:bound-term(opr) List. ((∀bt:bound-term(opr). ((bt ∈ bts)  P[snd(bt)]))  (∀f:opr. P[mkterm(f;bts)])))
   {∀t:term(opr). P[t]})

Definition: hereditarily
hereditarily(opr;s.P[s];t) ==  P[t] ∧ (∀s:term(opr). (s <<  P[s]))

Lemma: hereditarily_wf
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[t:term(opr)].  (hereditarily(opr;s.P[s];t) ∈ ℙ)

Lemma: hereditarily_functionality_wrt_subterm
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].  ∀t,s:term(opr).  (s <<  hereditarily(opr;s.P[s];t)  hereditarily(opr;s.P[s];s))

Lemma: hereditarily-varterm
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[v:{v:varname()| ¬(v nullvar() ∈ varname())} ].
  (hereditarily(opr;s.P[s];varterm(v)) ⇐⇒ P[varterm(v)])

Lemma: hereditarily-mkterm
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].
  ∀f:opr. ∀bts:bound-term(opr) List.
    (hereditarily(opr;s.P[s];mkterm(f;bts))
    ⇐⇒ P[mkterm(f;bts)] ∧ (∀bt:bound-term(opr). ((bt ∈ bts)  hereditarily(opr;s.P[s];snd(bt)))))

Definition: hered-term
hered-term(opr;t.P[t]) ==  {t:term(opr)| hereditarily(opr;s.P[s];t)} 

Lemma: hered-term_wf
[opr:Type]. ∀[P:term(opr) ⟶ ℙ].  (hered-term(opr;t.P[t]) ∈ Type)

Definition: bound-terms-accum
bound-terms-accum(L,bt.f[L; bt];param,bndtrm.g[param; bndtrm];bts) ==  dep-accum(L,bt.f[L; bt];a,bt.g[a; bt];bts)

Lemma: bound-terms-accum_wf
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[Param:Type]. ∀[C:Param ⟶ (varname() List × hered-term(opr;t.P[t])) ⟶ Type].
[bts:(varname() List × hered-term(opr;t.P[t])) List].
[f:very-dep-fun(Param;varname() List × hered-term(opr;t.P[t]);a,bt.C[a;bt])]. ∀[g:a:Param
                                                                                   ⟶ bt:{bt:varname() List
                                                                                          × hered-term(opr;t.P[t])| 
                                                                                          (bt ∈ bts)} 
                                                                                   ⟶ C[a;bt]].
  (bound-terms-accum(L,bt.f[L;bt];a,bt.g[a;bt];bts)
   ∈ {L:(a:Param × b:varname() List × hered-term(opr;t.P[t]) × C[a;b]) List| 
      vdf-eq(Param;f;L) ∧ (map(λx.(fst(snd(x)));L) bts ∈ ((varname() List × hered-term(opr;t.P[t])) List))} )

Definition: hered-term-accum
hered-term-accum(par,vars,v.varcase[par;
                                    vars;
                                    v];
                 prm,vs,f,L.m[prm;
                              vs;
                              f;
                              L];
                 p0,ws,op,sofar,bt.param[p0;
                                         ws;
                                         op;
                                         sofar;
                                         bt];
                 param;
                 bndtrm) ==
  let vs,t bndtrm 
  in case t
      of inl(v) =>
      varcase[param;
              vs;
              v]
      inr(pr) =>
      let f,bts pr 
      in let bound-terms-accum(sofar,bt.param[param;
                                                  vs;
                                                  f;
                                                  sofar;
                                                  bt];p',bt.hered-term-accum(par,vars,v.varcase[par;
                                                                                                vars;
                                                                                                v];
                                                                             prm,vs,f,L.m[prm;
                                                                                          vs;
                                                                                          f;
                                                                                          L];
                                                                             p0,ws,op,sofar,bt.param[p0;
                                                                                                     ws;
                                                                                                     op;
                                                                                                     sofar;
                                                                                                     bt];
                                                                             p';
                                                                             bt);bts) in
             m[param;
               vs;
               f;
               L]

Lemma: hered-term-accum_wf
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[Param:Type]. ∀[C:Param ⟶ (varname() List × hered-term(opr;t.P[t])) ⟶ Type].
[nextp:Param ⟶ (varname() List) ⟶ opr ⟶ very-dep-fun(Param;varname() List × hered-term(opr;t.P[t]);a,bt.C[a;bt])].
[m:a:Param
    ⟶ vs:(varname() List)
    ⟶ f:opr
    ⟶ L:{L:(a:Param × bt:varname() List × hered-term(opr;t.P[t]) × C[a;bt]) List| 
          vdf-eq(Param;nextp vs f;L) ∧ hereditarily(opr;s.P[s];mkterm(f;map(λx.(fst(snd(x)));L)))} 
    ⟶ C[a;<vs, mkterm(f;map(λx.(fst(snd(x)));L))>]]. ∀[varcase:a:Param
                                                             ⟶ vs:(varname() List)
                                                             ⟶ v:{v:varname()| 
                                                                   (v nullvar() ∈ varname())) ∧ P[varterm(v)]} 
                                                             ⟶ C[a;<vs, varterm(v)>]]. ∀[p:Param].
[bt:varname() List × hered-term(opr;t.P[t])].
  (hered-term-accum(p,vs,v.varcase[p;vs;v]; prm,vs,f,L.m[prm;vs;f;L]; p0,ws,op,sofar,bt.nextp[p0;ws;op;sofar;bt]; p; bt)
   ∈ C[p;bt])

Lemma: hered-term-accum_wf2
[opr:Type]. ∀[P:term(opr) ⟶ ℙ]. ∀[Param:Type]. ∀[C:Param ⟶ hered-term(opr;t.P[t]) ⟶ Type].
[nextp:Param
        ⟶ (varname() List)
        ⟶ opr
        ⟶ very-dep-fun(Param;varname() List × hered-term(opr;t.P[t]);a,bt.C[a;snd(bt)])].
[m:a:Param
    ⟶ vs:(varname() List)
    ⟶ f:opr
    ⟶ L:{L:(a:Param × bt:varname() List × hered-term(opr;t.P[t]) × C[a;snd(bt)]) List| 
          vdf-eq(Param;nextp vs f;L) ∧ hereditarily(opr;s.P[s];mkterm(f;map(λx.(fst(snd(x)));L)))} 
    ⟶ C[a;mkterm(f;map(λx.(fst(snd(x)));L))]]. ∀[varcase:a:Param
                                                          ⟶ vs:(varname() List)
                                                          ⟶ v:{v:varname()| 
                                                                (v nullvar() ∈ varname())) ∧ P[varterm(v)]} 
                                                          ⟶ C[a;varterm(v)]]. ∀[p:Param]. ∀[t:hered-term(opr;t.P[t])].
  (hered-term-accum(p,vs,v.varcase[p;vs;v];
                    prm,vs,f,L.m[prm;vs;f;L];
                    p0,ws,op,sofar,bt.nextp[p0;ws;op;sofar;bt];
                    p;
                    <[], t>) ∈ C[p;t])

Lemma: term-accum-induction
[opr,P:Type]. ∀[R:P ⟶ term(opr) ⟶ ℙ].
  ∀Q:P ⟶ opr ⟶ (varname() List) ⟶ ((t:term(opr) × p:P × R[p;t]) List) ⟶ P
    ((∀p:P. ∀v:{v:varname()| ¬(v nullvar() ∈ varname())} .  R[p;varterm(v)])
     (∀p:P. ∀f:opr. ∀bts:bound-term(opr) List. ∀L:{L:(t:term(opr) × p:P × R[p;t]) List| 
                                                     (||L|| ||bts|| ∈ ℤ)
                                                     ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                                                     ∧ (∀i:ℕ||L||
                                                          ((fst(snd(L[i]))) Q[p;f;fst(bts[i]);firstn(i;L)] ∈ P))} .
          R[p;mkterm(f;bts)])
     {∀t:term(opr). ∀p:P.  R[p;t]})

Definition: term-accum1
term-accum1(t)
p,f,vs,L.Q[p;
           f;
           vs;
           L]
varterm(v) with  varcase[p; v]
mkterm(f,bts) with  trs.mktermcase[p;
                                       f;
                                       bts;
                                       trs] ==
  letrec R(a)=case a
   of inl(v) =>
   λp.varcase[p; v]
   inr(pr) =>
   let f,bts pr 
   in λp.let trs accumulate (with value and list item bt):
                    let p' Q[p;
                               f;
                               fst(bt);
                               L] in
                        [<snd(bt), p', (snd(bt)) p'>]
                   over list:
                     bts
                   with starting value:
                    []) in
             mktermcase[p;
                        f;
                        bts;
                        trs] in
   R(t)

Lemma: term_accum1_varterm_lemma
p,v,M,vcase,Q:Top.
  (term-accum1(varterm(v))a,b,c,d.Q[a;b;c;d]varterm(v) with  vcase[v;p]mkterm(f,bts) with  L.M[p;f;bts;L] 
  vcase[v;p])

Lemma: term-accum-induction-ext
[opr,P:Type]. ∀[R:P ⟶ term(opr) ⟶ ℙ].
  ∀Q:P ⟶ opr ⟶ (varname() List) ⟶ ((t:term(opr) × p:P × R[p;t]) List) ⟶ P
    ((∀p:P. ∀v:{v:varname()| ¬(v nullvar() ∈ varname())} .  R[p;varterm(v)])
     (∀p:P. ∀f:opr. ∀bts:bound-term(opr) List. ∀L:{L:(t:term(opr) × p:P × R[p;t]) List| 
                                                     (||L|| ||bts|| ∈ ℤ)
                                                     ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                                                     ∧ (∀i:ℕ||L||
                                                          ((fst(snd(L[i]))) Q[p;f;fst(bts[i]);firstn(i;L)] ∈ P))} .
          R[p;mkterm(f;bts)])
     {∀t:term(opr). ∀p:P.  R[p;t]})

Lemma: term-accum1_wf
[opr,P:Type]. ∀[R:P ⟶ term(opr) ⟶ ℙ]. ∀[Q:P ⟶ opr ⟶ (varname() List) ⟶ ((t:term(opr) × p:P × R[p;t]) List) ⟶ P].
[varcase:∀p:P. ∀v:{v:varname()| ¬(v nullvar() ∈ varname())} .  R[p;varterm(v)]].
[mktermcase:∀p:P. ∀f:opr. ∀bts:bound-term(opr) List. ∀L:{L:(t:term(opr) × p:P × R[p;t]) List| 
                                                          (||L|| ||bts|| ∈ ℤ)
                                                          ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                                                          ∧ (∀i:ℕ||L||
                                                               ((fst(snd(L[i])))
                                                               Q[p;f;fst(bts[i]);firstn(i;L)]
                                                               ∈ P))} .
               R[p;mkterm(f;bts)]]. ∀[t:term(opr)].
  (term-accum1(t)
   p,f,vs,tr.Q[p;f;vs;tr]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  trs.mktermcase[p;f;bts;trs] ∈ p:P ⟶ R[p;t])

Definition: term-accum
term-accum(t with parm)
p,f,vs,tr.Q[p;
            f;
            vs;
            tr]
varterm(v) with  varcase[p; v]
mkterm(f,bts) with  trs.mktermcase[p;
                                       f;
                                       bts;
                                       trs] ==
  term-accum1(t)
  p,f,vs,tr.Q[p;
              f;
              vs;
              tr]
  varterm(v) with  varcase[p; v]
  mkterm(f,bts) with  trs.mktermcase[p;
                                         f;
                                         bts;
                                         trs] 
  parm

Lemma: term-accum_wf
[opr,P:Type]. ∀[R:P ⟶ term(opr) ⟶ ℙ]. ∀[Q:P ⟶ opr ⟶ (varname() List) ⟶ ((t:term(opr) × p:P × R[p;t]) List) ⟶ P].
[varcase:p:P ⟶ v:{v:varname()| ¬(v nullvar() ∈ varname())}  ⟶ R[p;varterm(v)]].
[mktermcase:p:P
             ⟶ f:opr
             ⟶ bts:(bound-term(opr) List)
             ⟶ L:{L:(t:term(opr) × p:P × R[p;t]) List| 
                   (||L|| ||bts|| ∈ ℤ)
                   ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                   ∧ (∀i:ℕ||L||. ((fst(snd(L[i]))) Q[p;f;fst(bts[i]);firstn(i;L)] ∈ P))} 
             ⟶ R[p;mkterm(f;bts)]]. ∀[t:term(opr)]. ∀[p:P].
  (term-accum(t with p)
   p,f,vs,tr.Q[p;f;vs;tr]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  trs.mktermcase[p;f;bts;trs] ∈ R[p;t])

Lemma: term_accum_varterm_lemma
p,M,v,varcase,Q:Top.
  (term-accum(varterm(v) with p)
   p,f,vs,xxx.Q[p;f;vs;xxx]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  xxx.M[p;f;bts;xxx] varcase[p;v])

Lemma: term_accum_mkterm_lemma
p,bts,f,M,varcase,Q:Top.
  (term-accum(mkterm(f;bts) with p)
   a,b,c,d.Q[a;b;c;d]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  trs.M[p;f;bts;trs] let trs accumulate (with value and list item bt):
                                                           let p' Q[p;f;fst(bt);d] in
                                                               d
                                                               [<snd(bt)
                                                                  p'
                                                                  term-accum(snd(bt) with p')
                                                                    a,b,c,d.Q[a;b;c;d]
                                                                    varterm(x) with  varcase[p;x]
                                                                    mkterm(f,bts) with  trs.M[p;f;bts;trs]>]
                                                          over list:
                                                            bts
                                                          with starting value:
                                                           []) in
                                                    M[p;f;bts;trs])

Definition: alpha-aux
alpha-aux(opr;vs;ws;a;b) ==
  case a
   of inl(v) =>
   case of inl(w) => ↑same-binding(vs;ws;v;w) inr(p) => False
   inr(p) =>
   case b
    of inl(w) =>
    False
    inr(q) =>
    let opa,abts 
    in let opb,bbts 
       in if abts is pair then if bbts is pair then let bta,morea abts 
                                                        in let btb,moreb bbts 
                                                           in let as,x bta 
                                                              in let bs,y btb 
                                                                 in (||as|| ||bs|| ∈ ℤ)
                                                                    ∧ alpha-aux(opr;rev(as) vs;rev(bs) ws;x;y)
                                                              ∧ alpha-aux(opr;vs;ws;mkterm(opa;morea);mkterm(opb;moreb))
                                 otherwise False otherwise if bbts is pair then False otherwise opa opb ∈ opr

Lemma: alpha-aux_wf
[opr:Type]. ∀[a,b:term(opr)]. ∀[vs,ws:varname() List].  (alpha-aux(opr;vs;ws;a;b) ∈ ℙ)

Lemma: sq_stable__alpha-aux
[opr:Type]. ∀a,b:term(opr). ∀vs,ws:varname() List.  SqStable(alpha-aux(opr;vs;ws;a;b))

Lemma: alpha-aux-mkterm
[opr:Type]
  ∀a,b:opr. ∀as,bs:bound-term(opr) List. ∀vs,ws:varname() List.
    (alpha-aux(opr;vs;ws;mkterm(a;as);mkterm(b;bs))
    ⇐⇒ (a b ∈ opr)
        ∧ (||as|| ||bs|| ∈ ℤ)
        ∧ (∀i:ℕ||as||
             (alpha-aux(opr;rev(fst(as[i])) vs;rev(fst(bs[i])) ws;snd(as[i]);snd(bs[i]))
             ∧ (||fst(as[i])|| ||fst(bs[i])|| ∈ ℤ))))

Lemma: alpha-aux-refl
[opr:Type]. ∀a:term(opr). ∀vs:varname() List.  alpha-aux(opr;vs;vs;a;a)

Lemma: alpha-aux-symm
[opr:Type]. ∀a,b:term(opr). ∀vs,ws:varname() List.  (alpha-aux(opr;vs;ws;a;b) ⇐⇒ alpha-aux(opr;ws;vs;b;a))

Lemma: alpha-aux-trans
[opr:Type]
  ∀a,b,c:term(opr). ∀us,vs,ws:varname() List.
    (alpha-aux(opr;us;vs;a;b)  alpha-aux(opr;vs;ws;b;c)  alpha-aux(opr;us;ws;a;c))

Definition: alpha-eq-terms
alpha-eq-terms(opr;a;b) ==  alpha-aux(opr;[];[];a;b)

Lemma: alpha-eq-terms_wf
[opr:Type]. ∀[a,b:term(opr)].  (alpha-eq-terms(opr;a;b) ∈ ℙ)

Lemma: alpha-eq-equiv-rel
[opr:Type]. EquivRel(term(opr);a,b.alpha-eq-terms(opr;a;b))

Lemma: alpha-eq-terms_transitivity
[opr:Type]. ∀a,b,c:term(opr).  (alpha-eq-terms(opr;a;b)  alpha-eq-terms(opr;b;c)  alpha-eq-terms(opr;a;c))

Lemma: alpha-eq-terms_inversion
[opr:Type]. ∀a,b:term(opr).  (alpha-eq-terms(opr;a;b)  alpha-eq-terms(opr;b;a))

Lemma: alpha-eq-terms_weakening
[opr:Type]. ∀a,b:term(opr).  ((a b ∈ term(opr))  alpha-eq-terms(opr;b;a))

Lemma: alpha-eq-terms_functionality
[opr:Type]
  ∀x1,x2,y1,y2:term(opr).
    (alpha-eq-terms(opr;x1;x2)
     alpha-eq-terms(opr;y1;y2)
     (alpha-eq-terms(opr;x1;y1) ⇐⇒ alpha-eq-terms(opr;x2;y2)))

Lemma: term-opr_functionality
[opr:Type]. ∀[t,t':term(opr)].
  (term-opr(t) term-opr(t') ∈ opr) supposing (alpha-eq-terms(opr;t;t') and (¬↑isvarterm(t)))

Lemma: isvarterm_functionality
[opr:Type]. ∀[t,t':term(opr)].  isvarterm(t) isvarterm(t') supposing alpha-eq-terms(opr;t;t')

Lemma: alpha-equal-varterm
[opr:Type]. ∀[v:{v:varname()| ¬(v nullvar() ∈ varname())} ]. ∀[t:term(opr)].
  varterm(v) ∈ term(opr) supposing alpha-eq-terms(opr;varterm(v);t)

Definition: free-vars-aux
free-vars-aux(bnds;t) ==
  case t
   of inl(v) =>
   if v ∈b bnds then [] else [v] fi 
   inr(p) =>
   let op,bts 
   in l-union-list(VarDeq;map(λbt.let vs,a bt 
                                  in free-vars-aux(rev(vs) bnds;a);bts))

Lemma: free-vars-aux_wf
[opr:Type]. ∀[t:term(opr)]. ∀[bnds:varname() List].
  (free-vars-aux(bnds;t) ∈ {v:varname()| ¬(v nullvar() ∈ varname())}  List)

Lemma: member-free-vars-aux-not-bound
[opr:Type]. ∀t:term(opr). ∀bnds:varname() List. ∀v:varname().  ((v ∈ free-vars-aux(bnds;t))  (v ∈ bnds)))

Lemma: member-free-vars-aux
[opr:Type]
  ∀t:term(opr). ∀v:varname(). ∀bnds:varname() List.
    ((v ∈ free-vars-aux(bnds;t)) ⇐⇒ (v ∈ free-vars-aux([];t)) ∧ (v ∈ bnds)))

Definition: free-vars
free-vars(t) ==  free-vars-aux([];t)

Lemma: free-vars_wf
[opr:Type]. ∀[t:term(opr)].  (free-vars(t) ∈ {v:varname()| ¬(v nullvar() ∈ varname())}  List)

Lemma: free-vars_functionality
[opr:Type]. ∀t1,t2:term(opr).  (alpha-eq-terms(opr;t1;t2)  (free-vars(t1) free-vars(t2) ∈ (varname() List)))

Definition: all-vars
all-vars(t) ==
  case t
   of inl(v) =>
   [v]
   inr(p) =>
   let op,bts 
   in accumulate (with value as and list item bt):
       let vs,a bt 
       in all-vars(a) ⋃ vs ⋃ as
      over list:
        bts
      with starting value:
       [])

Lemma: all-vars_wf
[opr:Type]. ∀[t:term(opr)].  (all-vars(t) ∈ varname() List)

Definition: binders-disjoint
binders-disjoint(opr;L;t) ==
  case t
   of inl(v) =>
   True
   inr(p) =>
   let op,bts 
   in (∀bt∈bts.l_disjoint(varname();fst(bt);L) ∧ binders-disjoint(opr;L;snd(bt)))

Lemma: binders-disjoint_wf
[opr:Type]. ∀[L:varname() List]. ∀[t:term(opr)].  (binders-disjoint(opr;L;t) ∈ ℙ)

Lemma: member-all-vars-mkterm
[opr:Type]
  ∀f:opr. ∀v:varname(). ∀bts:bound-term(opr) List.
    ((v ∈ all-vars(mkterm(f;bts))) ⇐⇒ ∃bt:bound-term(opr). ((bt ∈ bts) ∧ ((v ∈ fst(bt)) ∨ (v ∈ all-vars(snd(bt))))))

Lemma: member-free-vars-mkterm
[opr:Type]
  ∀f:opr. ∀v:varname(). ∀bts:bound-term(opr) List.
    ((v ∈ free-vars(mkterm(f;bts))) ⇐⇒ ∃bt:bound-term(opr). ((bt ∈ bts) ∧ (v ∈ free-vars(snd(bt))) ∧ (v ∈ fst(bt)))))

Lemma: free-vars-all-vars
[opr:Type]. ∀t:term(opr). ∀x:varname().  ((x ∈ free-vars(t))  (x ∈ all-vars(t)))

Definition: alpha-rename-aux
alpha-rename-aux(f;bnds;t) ==
  case t
   of inl(v) =>
   if v ∈b bnds then varterm(f v) else fi 
   inr(p) =>
   let op,bts 
   in eval bts' eager-map(λbt.let vs,a bt 
                                in <map(f;vs), alpha-rename-aux(f;rev(vs) bnds;a)>;bts) in
      mkterm(op;bts')

Lemma: alpha-rename-aux_wf
[opr:Type]. ∀[t:term(opr)]. ∀[bnds:varname() List].
  ∀f:{v:varname()| (v ∈ bnds all-vars(t))}  ⟶ varname()
    alpha-rename-aux(f;bnds;t) ∈ term(opr) 
    supposing ∀x:{v:varname()| (v ∈ bnds all-vars(t))} 
                (((f x) nullvar() ∈ varname())  (x nullvar() ∈ varname()))

Definition: alpha-rename
alpha-rename(f;t) ==  alpha-rename-aux(f;[];t)

Lemma: alpha-rename_wf
[opr:Type]. ∀[t:term(opr)].
  ∀f:{v:varname()| (v ∈ all-vars(t))}  ⟶ varname()
    alpha-rename(f;t) ∈ term(opr) 
    supposing ∀x:{v:varname()| (v ∈ all-vars(t))} (((f x) nullvar() ∈ varname())  (x nullvar() ∈ varname()))

Lemma: alpha-rename-equivalent
[opr:Type]
  ∀t:term(opr). ∀f:{v:varname()| (v ∈ all-vars(t))}  ⟶ varname().
    alpha-eq-terms(opr;alpha-rename(f;t);t) 
    supposing ((∀x:{v:varname()| (v ∈ all-vars(t))} ((f x ∈ free-vars(t))  ((f x) x ∈ varname())))
    ∧ (∀x:{v:varname()| (v ∈ all-vars(t))} (((f x) nullvar() ∈ varname())  (x nullvar() ∈ varname()))))
    ∧ Inj({v:varname()| (v ∈ all-vars(t))} ;varname();f)

Lemma: alpha-rename-binders-disjoint
[opr:Type]
  ∀L:varname() List. ∀t:term(opr). ∀f:{v:varname()| (v ∈ all-vars(t))}  ⟶ varname().
    ((∀x:{v:varname()| (v ∈ all-vars(t))} 
        ((((f x) nullvar() ∈ varname())  (x nullvar() ∈ varname())) ∧ (f x ∈ L))))
     binders-disjoint(opr;L;alpha-rename(f;t)))

Definition: alpha-rename-alist
alpha-rename-alist(t;L) ==
  snd(accumulate (with value and list item x):
       let vs,tab 
       in eval x' maybe_new_var(x;vs) in
          <[x' vs], [<x, x'> tab]>
      over list:
        L
      with starting value:
       <all-vars(t), []>))

Lemma: alpha-rename-alist_wf
[opr:Type]. ∀[t:term(opr)]. ∀[L:varname() List].  (alpha-rename-alist(t;L) ∈ (varname() × varname()) List)

Lemma: alpha-rename-alist-property
[opr:Type]
  ∀t:term(opr). ∀L:varname() List.
    ((∀x,x':varname().  ((<x, x'> ∈ alpha-rename-alist(t;L))  ((x ∈ L) ∧ (x' ∈ all-vars(t))))))
    ∧ (∀x,x',y,y':varname().
         ((<x, x'> ∈ alpha-rename-alist(t;L))
          (<y, y'> ∈ alpha-rename-alist(t;L))
          (x' y' ∈ varname())
          (x y ∈ varname()))))

Lemma: alpha-rename-alist-nonnullvar
[opr:Type]
  ∀t:term(opr). ∀L:varname() List. ∀x,x':varname().
    ((<x, x'> ∈ alpha-rename-alist(t;L))  (x' nullvar() ∈ varname())  (nullvar() ∈ L))

Lemma: alpha-rename-alist-property2
[opr:Type]
  ∀t:term(opr). ∀L:varname() List. ∀x:varname().  ((x ∈ L)  (∃x':varname(). (<x, x'> ∈ alpha-rename-alist(t;L))))

Definition: alpha-avoid
alpha-avoid(L;t) ==  alpha-rename(alist-map(VarDeq;alpha-rename-alist(t;L));t)

Lemma: alpha-avoid_wf
[opr:Type]. ∀[t:term(opr)]. ∀[L:varname() List].  alpha-avoid(L;t) ∈ term(opr) supposing ¬(nullvar() ∈ L)

Lemma: alpha-avoid-binders-disjoint
[opr:Type]. ∀L:varname() List. ((¬(nullvar() ∈ L))  (∀t:term(opr). binders-disjoint(opr;L;alpha-avoid(L;t))))

Lemma: alpha-avoid-equivalent
[opr:Type]. ∀t:term(opr). ∀L:varname() List.  alpha-eq-terms(opr;alpha-avoid(L;t);t) supposing ¬(nullvar() ∈ L)

Definition: replace-vars
replace-vars(s;t) ==
  case t
   of inl(v) =>
   case apply-alist(VarDeq;s;v) of inl(a) => inr(_) => t
   inr(p) =>
   let op,bts 
   in eval bts' eager-map(λbt.let vs,b bt 
                                in <vs, replace-vars(s;b)>;bts) in
      mkterm(op;bts')

Lemma: replace-vars_wf
[opr:Type]. ∀[t:term(opr)]. ∀[s:(varname() × term(opr)) List].  (replace-vars(s;t) ∈ term(opr))

Definition: equiv-substs
equiv-substs(opr;s1;s2) ==
  ∀x:varname()
    (isl(apply-alist(VarDeq;s1;x)) isl(apply-alist(VarDeq;s2;x))
    ∧ ((↑isl(apply-alist(VarDeq;s1;x)))
       alpha-eq-terms(opr;outl(apply-alist(VarDeq;s1;x));outl(apply-alist(VarDeq;s2;x)))))

Lemma: equiv-substs_wf
[opr:Type]. ∀[s1,s2:(varname() × term(opr)) List].  (equiv-substs(opr;s1;s2) ∈ ℙ)

Lemma: equiv-substs-equiv-rel
[opr:Type]. EquivRel((varname() × term(opr)) List;s1,s2.equiv-substs(opr;s1;s2))

Definition: vars-of-subst
vars-of-subst(s) ==
  l-union-list(VarDeq;map(λvt.let v,t vt 
                              in if eq_var(v;nullvar()) then free-vars(t) else insert(v;free-vars(t)) fi ;s))

Lemma: vars-of-subst_wf
[opr:Type]. ∀[s:(varname() × term(opr)) List].  (vars-of-subst(s) ∈ {v:varname()| ¬(v nullvar() ∈ varname())}  List)

Lemma: vars-of-subst-not-nullvar
[opr:Type]. ∀[s:(varname() × term(opr)) List].  (nullvar() ∈ vars-of-subst(s)))

Definition: subst-frame
subst-frame(s;t) ==  alpha-avoid(vars-of-subst(s);t)

Lemma: subst-frame_wf
[opr:Type]. ∀[t:term(opr)]. ∀[s:(varname() × term(opr)) List].  (subst-frame(s;t) ∈ term(opr))

Lemma: subst-frame-alpha
[opr:Type]. ∀t:term(opr). ∀s:(varname() × term(opr)) List.  alpha-eq-terms(opr;subst-frame(s;t);t)

Lemma: subst-frame-binders-disjoint
[opr:Type]. ∀t:term(opr). ∀s:(varname() × term(opr)) List.  binders-disjoint(opr;vars-of-subst(s);subst-frame(s;t))

Definition: subst-term
subst-term(s;t) ==  replace-vars(s;subst-frame(s;t))

Lemma: subst-term_wf
[opr:Type]. ∀[t:term(opr)]. ∀[s:(varname() × term(opr)) List].  (subst-term(s;t) ∈ term(opr))

Lemma: subst-term_functionality
[opr:Type]
  ∀t1,t2:term(opr). ∀s1,s2:(varname() × term(opr)) List.
    (alpha-eq-terms(opr;t1;t2)  equiv-substs(opr;s1;s2)  alpha-eq-terms(opr;subst-term(s1;t1);subst-term(s2;t2)))

Definition: correct-sort-arity
correct-sort-arity(sort;arity;t) ==
  (¬↑isvarterm(t))
   let bts term-bts(t) in
      let term-opr(t) in
      (||bts|| ||arity f|| ∈ ℤ)
      ∧ (∀i:ℕ||bts||. ((||fst(bts[i])|| (fst(arity f[i])) ∈ ℤ) ∧ ((sort (snd(bts[i]))) (snd(arity f[i])) ∈ ℤ)))

Lemma: correct-sort-arity_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[t:term(opr)].
  (correct-sort-arity(sort;arity;t) ∈ ℙ)

Definition: wf-term
wf-term(arity;sort;t) ==
  case t
   of inl(v) =>
   tt
   inr(p) =>
   let f,bts 
   in eval nms arity in
      (||nms|| =z ||bts||)
      ∧b (∀nm_bt∈zip(nms;bts).let nm,bt nm_bt 
                              in let vs,b bt 
                                 in (fst(nm) =z ||vs||) ∧b (sort =z snd(nm)) ∧b wf-term(arity;sort;b))_b

Lemma: wf-term_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[t:term(opr)].  (wf-term(arity;sort;t) ∈ 𝔹)

Lemma: wf_term_var_lemma
v,arity,sort:Top.  (wf-term(arity;sort;varterm(v)) tt)

Lemma: assert-wf-mkterm
[opr:Type]
  ∀sort:term(opr) ⟶ ℕ. ∀arity:opr ⟶ ((ℕ × ℕList). ∀f:opr. ∀bts:(varname() List × term(opr)) List.
    uiff(↑wf-term(arity;sort;mkterm(f;bts));(||bts|| ||arity f|| ∈ ℤ)
    ∧ (∀i:ℕ||bts||
         ((||fst(bts[i])|| (fst(arity f[i])) ∈ ℤ)
         ∧ ((sort (snd(bts[i]))) (snd(arity f[i])) ∈ ℤ)
         ∧ (↑wf-term(arity;sort;snd(bts[i]))))))

Definition: wfterm
wfterm(opr;sort;arity) ==  {t:term(opr)| ↑wf-term(arity;sort;t)} 

Lemma: wfterm_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)].  (wfterm(opr;sort;arity) ∈ Type)

Lemma: wf-term-hereditarily-correct-sort-arity
[opr:Type]
  ∀sort:term(opr) ⟶ ℕ. ∀arity:opr ⟶ ((ℕ × ℕList). ∀t:term(opr).
    (↑wf-term(arity;sort;t) ⇐⇒ hereditarily(opr;s.correct-sort-arity(sort;arity;s);t))

Lemma: wfterm-hered-correct-sort-arity
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)].
  wfterm(opr;sort;arity) ≡ hered-term(opr;t.correct-sort-arity(sort;arity;t))

Definition: wf-bound-terms
wf-bound-terms(opr;sort;arity;f) ==
  {bts:(varname() List × wfterm(opr;sort;arity)) List| 
   (||bts|| ||arity f|| ∈ ℤ)
   ∧ (∀i:ℕ||bts||. ((||fst(bts[i])|| (fst(arity f[i])) ∈ ℤ) ∧ ((sort (snd(bts[i]))) (snd(arity f[i])) ∈ ℤ)))} 

Lemma: wf-bound-terms_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[f:opr].
  (wf-bound-terms(opr;sort;arity;f) ∈ Type)

Definition: mkwfterm
mkwfterm(f;bts) ==  mkterm(f;bts)

Lemma: mkwfterm_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[f:opr]. ∀[bts:wf-bound-terms(opr;sort;arity;f)].
  (mkwfterm(f;bts) ∈ wfterm(opr;sort;arity))

Definition: wfbts
wfbts(t) ==  term-bts(t)

Lemma: wfbts_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[t:wfterm(opr;sort;arity)].
  wfbts(t) ∈ wf-bound-terms(opr;sort;arity;term-opr(t)) supposing ¬↑isvarterm(t)

Definition: wfterm-accum
wfterm-accum(param;t)
p,vrs,v.varcase[p;
                vrs;
                v]
prm,vs,f,L.m[prm;
             vs;
             f;
             L]
p0,ws,op,sofar,bt.nextp[p0;
                        ws;
                        op;
                        sofar;
                        bt] ==
  hered-term-accum(p,vs,v.varcase[p;
                                  vs;
                                  v];
                   prm,vs,f,L.m[prm;
                                vs;
                                f;
                                L];
                   p0,ws,op,sofar,bt.nextp[p0;
                                           ws;
                                           op;
                                           sofar;
                                           bt];
                   param;
                   <[], t>)

Lemma: wfterm-accum_wf
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[Param:Type]. ∀[C:Param
                                                                                        ⟶ wfterm(opr;sort;arity)
                                                                                        ⟶ Type].
[nextp:Param
        ⟶ (varname() List)
        ⟶ opr
        ⟶ very-dep-fun(Param;varname() List × wfterm(opr;sort;arity);a,bt.C[a;snd(bt)])].
[m:a:Param
    ⟶ vs:(varname() List)
    ⟶ f:opr
    ⟶ L:{L:(a:Param × bt:varname() List × wfterm(opr;sort;arity) × C[a;snd(bt)]) List| 
          vdf-eq(Param;nextp vs f;L) ∧ (↑wf-term(arity;sort;mkterm(f;map(λx.(fst(snd(x)));L))))} 
    ⟶ C[a;mkterm(f;map(λx.(fst(snd(x)));L))]]. ∀[varcase:a:Param
                                                          ⟶ vs:(varname() List)
                                                          ⟶ v:{v:varname()| ¬(v nullvar() ∈ varname())} 
                                                          ⟶ C[a;varterm(v)]]. ∀[p:Param]. ∀[t:wfterm(opr;sort;arity)].
  (wfterm-accum(p;t)
   p,vs,v.varcase[p;vs;v]
   prm,vs,f,L.m[prm;vs;f;L]
   p0,ws,op,sofar,bt.nextp[p0;ws;op;sofar;bt] ∈ C[p;t])

Lemma: term-ind_wf_wfterm
[opr:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[P:wfterm(opr;sort;arity) ⟶ ℙ].
[varcase:∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)]].
[mktermcase:∀f:opr. ∀bts:wf-bound-terms(opr;sort;arity;f).  ((∀i:ℕ||bts||. P[snd(bts[i])])  P[mkwfterm(f;bts)])].
[t:wfterm(opr;sort;arity)].
  (term-ind(x.varcase[x];f,bts,r.mktermcase[f;bts;r];t) ∈ P[t])

Lemma: wf-term-induction
[opr:Type]
  ∀sort:term(opr) ⟶ ℕ. ∀arity:opr ⟶ ((ℕ × ℕList).
    ∀[P:wfterm(opr;sort;arity) ⟶ ℙ]
      ((∀v:{v:varname()| ¬(v nullvar() ∈ varname())} P[varterm(v)])
       (∀f:opr. ∀bts:wf-bound-terms(opr;sort;arity;f).  ((∀i:ℕ||bts||. P[snd(bts[i])])  P[mkwfterm(f;bts)]))
       {∀t:wfterm(opr;sort;arity). P[t]})

Lemma: term-accum_wf_wfterm_0
[opr,P:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[R:P ⟶ wfterm(opr;sort;arity) ⟶ ℙ].
[Q:P ⟶ opr ⟶ (varname() List) ⟶ ((t:term(opr) × p:P × R[p;t] supposing ↑wf-term(arity;sort;t)) List) ⟶ P].
[varcase:p:P ⟶ v:{v:varname()| ¬(v nullvar() ∈ varname())}  ⟶ R[p;varterm(v)]].
[mktermcase:p:P
             ⟶ f:opr
             ⟶ bts:wf-bound-terms(opr;sort;arity;f)
             ⟶ L:{L:(t:wfterm(opr;sort;arity) × p:P × R[p;t]) List| 
                   (||L|| ||bts|| ∈ ℤ)
                   ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                   ∧ (∀i:ℕ||L||. ((fst(snd(L[i]))) Q[p;f;fst(bts[i]);firstn(i;L)] ∈ P))} 
             ⟶ R[p;mkwfterm(f;bts)]]. ∀[t:wfterm(opr;sort;arity)]. ∀[p:P].
  (term-accum(t with p)
   p,f,vs,tr.Q[p;f;vs;tr]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  trs.mktermcase[p;f;bts;trs] ∈ R[p;t])

Lemma: term-accum_wf_wfterm
[opr,P:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[R:P ⟶ wfterm(opr;sort;arity) ⟶ ℙ].
[Q:P
    ⟶ f:opr
    ⟶ vs:(varname() List)
    ⟶ {L:(t:wfterm(opr;sort;arity) × p:P × R[p;t]) List| 
        ||L|| < ||arity f||
        ∧ (||vs|| (fst(arity f[||L||])) ∈ ℤ)
        ∧ (∀i:ℕ||L||. ((sort (fst(L[i]))) (snd(arity f[i])) ∈ ℤ))} 
    ⟶ P]. ∀[varcase:p:P ⟶ v:{v:varname()| ¬(v nullvar() ∈ varname())}  ⟶ R[p;varterm(v)]].
[mktermcase:p:P
             ⟶ f:opr
             ⟶ bts:wf-bound-terms(opr;sort;arity;f)
             ⟶ L:{L:(t:wfterm(opr;sort;arity) × p:P × R[p;t]) List| 
                   (||L|| ||bts|| ∈ ℤ)
                   ∧ (∀i:ℕ||L||. ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                   ∧ (∀i:ℕ||L||. ((fst(snd(L[i]))) Q[p;f;fst(bts[i]);firstn(i;L)] ∈ P))} 
             ⟶ R[p;mkwfterm(f;bts)]]. ∀[t:wfterm(opr;sort;arity)]. ∀[p:P].
  (term-accum(t with p)
   p,f,vs,tr.Q[p;f;vs;tr]
   varterm(x) with  varcase[p;x]
   mkterm(f,bts) with  trs.mktermcase[p;f;bts;trs] ∈ R[p;t])

Lemma: wf-term-accum-induction
[opr,P:Type]. ∀[sort:term(opr) ⟶ ℕ]. ∀[arity:opr ⟶ ((ℕ × ℕList)]. ∀[R:P ⟶ wfterm(opr;sort;arity) ⟶ ℙ].
  ∀Q:P
     ⟶ f:opr
     ⟶ vs:(varname() List)
     ⟶ {L:(t:wfterm(opr;sort;arity) × p:P × R[p;t]) List| 
         ||L|| < ||arity f||
         ∧ (||vs|| (fst(arity f[||L||])) ∈ ℤ)
         ∧ (∀i:ℕ||L||. ((sort (fst(L[i]))) (snd(arity f[i])) ∈ ℤ))} 
     ⟶ P
    ((∀p:P. ∀v:{v:varname()| ¬(v nullvar() ∈ varname())} .  R[p;varterm(v)])
     (∀p:P. ∀f:opr. ∀bts:wf-bound-terms(opr;sort;arity;f). ∀L:{L:(t:wfterm(opr;sort;arity) × p:P × R[p;t]) List| 
                                                                 (||L|| ||bts|| ∈ ℤ)
                                                                 ∧ (∀i:ℕ||L||
                                                                      ((fst(L[i])) (snd(bts[i])) ∈ term(opr)))
                                                                 ∧ (∀i:ℕ||L||
                                                                      ((fst(snd(L[i])))
                                                                      Q[p;f;fst(bts[i]);firstn(i;L)]
                                                                      ∈ P))} .
          R[p;mkwfterm(f;bts)])
     (∀p:P. ∀t:wfterm(opr;sort;arity).  R[p;t]))



Home Index