(* ========================================================================= *)
(*  More definitions and theorems and tactics about lists.                   *)
(*                                                                           *)
(*  Author: Marco Maggesi                                                    *)
(*          University of Florence, Italy                                    *)
(*          http://www.math.unifi.it/~maggesi/                               *)
(*                                                                           *)
(*          (c) Copyright, Marco Maggesi, 2005-2007                          *)
(* ========================================================================= *)
parse_as_infix ("::",(23,"right"));;
override_interface("::",`CONS`);;
(* ------------------------------------------------------------------------- *)
(*  Some handy tactics.                                                      *)
(* ------------------------------------------------------------------------- *)
let ASSERT_TAC tm = SUBGOAL_THEN tm ASSUME_TAC;;
let SUFFICE_TAC thl tm =
  SUBGOAL_THEN tm (fun th -> MESON_TAC (th :: thl));;
let LIST_CASES_TAC =
  let th = prove (`!P. P [] /\ (!h t. P (h :: t)) ==> !l. P l`,
                  GEN_TAC THEN STRIP_TAC THEN
                  LIST_INDUCT_TAC THEN ASM_REWRITE_TAC [])
  in
  MATCH_MP_TAC th THEN CONJ_TAC THENL
  [ALL_TAC; GEN_TAC THEN GEN_TAC];;
 
let NOT_MEM_DELETE1 = prove
  (`!t h x. ~MEM x t ==> ~MEM x (
DELETE1 h t)`,
   LIST_INDUCT_TAC THEN GEN_TAC THEN GEN_TAC THEN
   REWRITE_TAC [
MEM; 
DELETE1] THEN
   COND_CASES_TAC THEN REWRITE_TAC [
MEM; DE_MORGAN_THM] THEN
   STRIP_TAC THEN ASM_SIMP_TAC []);;
 
let MEM_DELETE1 = prove
  (`!l x y:A. 
MEM x l /\ ~(x = y) ==> 
MEM x (
DELETE1 y l)`,
   LIST_INDUCT_TAC THEN REWRITE_TAC [
MEM; 
DELETE1] THEN
   GEN_TAC THEN GEN_TAC THEN COND_CASES_TAC THENL
   [EXPAND_TAC "h" THEN MESON_TAC [];
    REWRITE_TAC [
MEM] THEN ASM_MESON_TAC []]);;
 
let LIST_UNIQ = prove
  (`
LIST_UNIQ [] /\
   (!x. 
LIST_UNIQ [x]) /\
   (!x xs. 
LIST_UNIQ (x :: xs) <=> ~MEM x xs /\ 
LIST_UNIQ xs)`,
   SIMP_TAC [LIST_UNIQ_RULES; 
MEM] THEN
   REPEAT GEN_TAC THEN EQ_TAC THENL
   [ONCE_REWRITE_TAC [ISPEC `h :: t` LIST_UNIQ_CASES] THEN
    REWRITE_TAC [
CONS_11; 
NOT_CONS_NIL] THEN
    DISCH_THEN (CHOOSE_THEN CHOOSE_TAC) THEN ASM_REWRITE_TAC [];
    SIMP_TAC [LIST_UNIQ_RULES]]);;
 
let LIST_UNIQ_COUNT = prove
  (`!l. 
LIST_UNIQ l <=> (!x:A. 
COUNT x l = if 
MEM x l then 1 else 0)`,
   let IFF_EXPAND = MESON [] `(p <=> q) <=> (p ==> q) /\ (q ==> p)` in
   REWRITE_TAC [IFF_EXPAND; 
FORALL_AND_THM] THEN CONJ_TAC THENL
   [MATCH_MP_TAC LIST_UNIQ_INDUCT THEN REWRITE_TAC [
COUNT; 
MEM] THEN
    REPEAT STRIP_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
ONE];
    LIST_INDUCT_TAC THEN REWRITE_TAC [
LIST_UNIQ; 
COUNT; 
MEM] THEN
    DISCH_TAC THEN FIRST_ASSUM (MP_TAC o SPEC `h:A`) THEN
    SIMP_TAC [
MEM_COUNT; 
ONE; 
SUC_INJ] THEN DISCH_TAC THEN
    FIRST_X_ASSUM MATCH_MP_TAC THEN GEN_TAC THEN
    FIRST_ASSUM (MP_TAC o SPEC `x:A`) THEN
    REWRITE_TAC [
MEM_COUNT] THEN ARITH_TAC]);;