let aacons_tm = `CONS:A -> A list -> A list` ;;
let HD_CONV conv tm = 
  let h::rest = dest_list tm in
  let ty = type_of h in  
  let thm = conv h in
  let thm2 = REFL (mk_list(rest,ty)) in
  let cs = inst [ty,aty] aacons_tm in
    MK_COMB ((AP_TERM cs thm),thm2);;
let TL_CONV conv tm = 
(*   try *)
    let h::t = dest_list tm in
    let lty = type_of h in
    let cs = inst [lty,aty] aacons_tm in
      MK_COMB ((AP_TERM cs (REFL h)), (LIST_CONV conv (mk_list(t,lty))))
(*   with _ -> failwith "TL_CONV" *)
let rec EL_CONV conv i tm = 
  if i = 0 then HD_CONV conv tm
  else 
    let h::t = dest_list tm in
    let lty = type_of h in
    let cs = inst [lty,aty] aacons_tm in
      MK_COMB ((AP_TERM cs (REFL h)), (EL_CONV conv (i - 1) (mk_list(t,lty))))
(*
  let conv = (REWRITE_CONV[ARITH_RULE `x + x = &2 * x`])
  let tm = `[&5 + &5; &6 + &6; &7 + &7]`
  HD_CONV conv tm 
  TL_CONV conv tm 
  HD_CONV(TL_CONV conv) tm 
  CONS_CONV conv tm
  EL_CONV conv 0 tm
  EL_CONV conv 1 tm
  EL_CONV conv 2 tm
*)
(* }}} *)
let REMOVE = new_recursive_definition list_RECURSION
  `(REMOVE x [] = []) /\ 
   (REMOVE x (CONS (h:A) t) = 
     let rest = REMOVE x t in
       if x = h then rest else CONS h rest)`;;let LENGTH_1 = prove_by_refinement(
  `!l. (
LENGTH l = 1) <=> ?x. l = [x]`,
(* {{{ Proof *)
[
  LIST_INDUCT_TAC;
  EQ_TAC;
  MESON_TAC[
LENGTH;ARITH_RULE `~(1 = 0)`];
  MESON_TAC[
NOT_CONS_NIL];
  EQ_TAC;
  REWRITE_TAC[
LENGTH;ARITH_RULE `~(0 = 1)`];
  REWRITE_TAC[
LENGTH];
  STRIP_TAC;
  CLAIM `
LENGTH t = 0`;
  POP_ASSUM MP_TAC THEN ARITH_TAC;
  STRIP_TAC;
  CLAIM `t = []`;
  ASM_MESON_TAC[
LENGTH_0];
  STRIP_TAC;
  ASM_REWRITE_TAC[];
  ASM_MESON_TAC[];
  STRIP_TAC;
  ASM_MESON_TAC[
LENGTH;
ONE];
]);;
 
let LIST_TRI = prove_by_refinement(
  `!p. (p = []) \/ (?x. p = [x:A]) \/ (?x y t. p = CONS x (CONS y t))`,
(* {{{ Proof *)
[
  STRIP_TAC;
  DISJ_CASES_TAC (ISPEC `p:A list` 
list_CASES);
  ASM_REWRITE_TAC[];
  POP_ASSUM MP_TAC THEN STRIP_TAC;
  DISJ_CASES_TAC (ISPEC `t:A list` 
list_CASES);  
  ASM_MESON_TAC[];
  ASM_MESON_TAC[];
]);;
 
let LENGTH_PAIR = prove_by_refinement(
  `!p. (
LENGTH p = 2) <=> ?h t. p = [h:A; t]`,
(* {{{ Proof *)
[
  STRIP_TAC THEN EQ_TAC;
  STRIP_TAC;
  MP_TAC (ISPEC `p:A list` 
list_CASES);
  STRIP_TAC;
  ASM_MESON_TAC[
LENGTH_0;ARITH_RULE `~(2 = 0)`];
  MP_TAC (ISPEC `t:A list` 
list_CASES);
  STRIP_TAC;
  ASM_MESON_TAC[
LENGTH_1;ARITH_RULE `~(1 = 2)`];
  MP_TAC (ISPEC `t':A list` 
list_CASES);  
  STRIP_TAC;
  EXISTS_TAC `h:A`;
  EXISTS_TAC `h':A`;
  ASM_MESON_TAC[];
  CLAIM `p = CONS h (CONS h' (CONS h'' t''))`;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `2 < 
LENGTH p`; 
  POP_ASSUM SUBST1_TAC;
  REWRITE_TAC[
LENGTH];
  ARITH_TAC;
  ASM_MESON_TAC[
LT_REFL];
  STRIP_TAC;
  ASM_REWRITE_TAC[
LENGTH];
  ARITH_TAC;
]);;
 
let LENGTH_SING = prove_by_refinement(
  `!p. (
LENGTH p = 1) <=> ?h. p = [h:A]`,
(* {{{ Proof *)
[
  STRIP_TAC THEN EQ_TAC;
  STRIP_TAC;
  MP_TAC (ISPEC `p:A list` 
list_CASES);
  STRIP_TAC;
  ASM_MESON_TAC[
LENGTH_0;ARITH_RULE `~(1 = 0)`];
  MP_TAC (ISPEC `t:A list` 
list_CASES);
  STRIP_TAC;
  EXISTS_TAC `h:A`;
  ASM_MESON_TAC[];
  CLAIM `p = CONS h (CONS h' t')`;
  ASM_MESON_TAC[];
  STRIP_TAC;
  CLAIM `1 < 
LENGTH p`; 
  POP_ASSUM SUBST1_TAC;
  REWRITE_TAC[
LENGTH];
  ARITH_TAC;
  ASM_REWRITE_TAC[];
  ARITH_TAC;
  STRIP_TAC;
  ASM_REWRITE_TAC[
LENGTH;];
  ARITH_TAC;
]);;
 
let TL_NIL = prove_by_refinement(
  `!l. ~(l = []) ==> ((
TL l = []) <=> ?x. l = [x])`,
(* {{{ Proof *)
[
  REPEAT STRIP_TAC THEN EQ_TAC;
  CLAIM `?h t. l = CONS h t`;
  ASM_MESON_TAC[
list_CASES];
  STRIP_TAC;
  ASM_REWRITE_TAC[
TL];
  ASM_MESON_TAC !LIST_REWRITES;
  ASM_MESON_TAC !LIST_REWRITES;
]);;