(* ========================================================================= *)
(* 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];;
(* ------------------------------------------------------------------------- *)
(* Occasionally useful stuff. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Well-founded induction on lists. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Delete one element from a list. *)
(* ------------------------------------------------------------------------- *)
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 []]);;
(* ------------------------------------------------------------------------- *)
(* Counting occurrences of a given element in a list. *)
(* ------------------------------------------------------------------------- *)
(* ------------------------------------------------------------------------- *)
(* Duplicates in a list. *)
(* ------------------------------------------------------------------------- *)
let LIST_UNIQ_RULES, LIST_UNIQ_INDUCT, LIST_UNIQ_CASES =
new_inductive_definition
`LIST_UNIQ [] /\
(!x xs. LIST_UNIQ xs /\ ~MEM x xs ==> LIST_UNIQ (x :: xs))`;;
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]]);;
(* !!! forse e' meglio con IMP? *)
(* Magari LIST_UNIQ_COUNT + COUNT_LIST_UNIQ *)
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]);;
(* ------------------------------------------------------------------------- *)
(* Lists and finite sets. *)
(* ------------------------------------------------------------------------- *)