(* ========================================================================= *)
(* Theory of lists, plus characters and strings as lists of characters. *)
(* *)
(* John Harrison, University of Cambridge Computer Laboratory *)
(* *)
(* (c) Copyright, University of Cambridge 1998 *)
(* (c) Copyright, John Harrison 1998-2007 *)
(* ========================================================================= *)
needs "ind_types.ml";;
(* ------------------------------------------------------------------------- *)
(* Standard tactic for list induction using MATCH_MP_TAC list_INDUCT *)
(* ------------------------------------------------------------------------- *)
let LIST_INDUCT_TAC =
let list_INDUCT = prove
(`!P:(A)list->bool. P [] /\ (!h t. P t ==> P (CONS h t)) ==> !l. P l`,
MATCH_ACCEPT_TAC
list_INDUCT) in
MATCH_MP_TAC
list_INDUCT THEN
CONJ_TAC THENL [ALL_TAC; GEN_TAC THEN GEN_TAC THEN DISCH_TAC];;
(* ------------------------------------------------------------------------- *)
(* Basic definitions. *)
(* ------------------------------------------------------------------------- *)
let HD = new_recursive_definition list_RECURSION
`HD(CONS (h:A) t) = h`;;
let TL = new_recursive_definition list_RECURSION
`TL(CONS (h:A) t) = t`;;
let APPEND = new_recursive_definition list_RECURSION
`(!l:(A)list. APPEND [] l = l) /\
(!h t l. APPEND (CONS h t) l = CONS h (APPEND t l))`;;
let MAP = new_recursive_definition list_RECURSION
`(!f:A->B. MAP f NIL = NIL) /\
(!f h t. MAP f (CONS h t) = CONS (f h) (MAP f t))`;;
let LAST = new_recursive_definition list_RECURSION
`LAST (CONS (h:A) t) = if t = [] then h else LAST t`;;
let NULL = new_recursive_definition list_RECURSION
`(NULL [] = T) /\
(NULL (CONS h t) = F)`;;
let ALL = new_recursive_definition list_RECURSION
`(ALL P [] = T) /\
(ALL P (CONS h t) <=> P h /\ ALL P t)`;;
let EX = new_recursive_definition list_RECURSION
`(EX P [] = F) /\
(EX P (CONS h t) <=> P h \/ EX P t)`;;
let MEM = new_recursive_definition list_RECURSION
`(MEM x [] <=> F) /\
(MEM x (CONS h t) <=> (x = h) \/ MEM x t)`;;
let ALL2_DEF = new_recursive_definition list_RECURSION
`(ALL2 P [] l2 <=> (l2 = [])) /\
(ALL2 P (CONS h1 t1) l2 <=>
if l2 = [] then F
else P h1 (HD l2) /\ ALL2 P t1 (TL l2))`;;
let ALL2 = prove
(`(
ALL2 P [] [] <=> T) /\
(
ALL2 P (CONS h1 t1) [] <=> F) /\
(
ALL2 P [] (CONS h2 t2) <=> F) /\
(
ALL2 P (CONS h1 t1) (CONS h2 t2) <=> P h1 h2 /\
ALL2 P t1 t2)`,
REWRITE_TAC[distinctness "list";
ALL2_DEF; HD; TL]);;
let MAP2_DEF = new_recursive_definition list_RECURSION
`(MAP2 f [] l = []) /\
(MAP2 f (CONS h1 t1) l = CONS (f h1 (HD l)) (MAP2 f t1 (TL l)))`;;
let EL = new_recursive_definition num_RECURSION
`(EL 0 l = HD l) /\
(EL (SUC n) l = EL n (TL l))`;;
let ZIP_DEF = new_recursive_definition list_RECURSION
`(ZIP [] l2 = []) /\
(ZIP (CONS h1 t1) l2 = CONS (h1,HD l2) (ZIP t1 (TL l2)))`;;
(* ------------------------------------------------------------------------- *)
(* Various trivial theorems. *)
(* ------------------------------------------------------------------------- *)
let CONS_11 = prove
(`!(h1:A) h2 t1 t2. (CONS h1 t1 = CONS h2 t2) <=> (h1 = h2) /\ (t1 = t2)`,
REWRITE_TAC[injectivity "list"]);;
let MAP_o = prove
(`!f:A->B. !g:B->C. !l.
MAP (g o f) l =
MAP g (
MAP f l)`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
ASM_REWRITE_TAC[
MAP;
o_THM]);;
let MAP_EQ = prove
(`!f g l.
ALL (\x. f x = g x) l ==> (
MAP f l =
MAP g l)`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
REWRITE_TAC[
MAP;
ALL] THEN ASM_MESON_TAC[]);;
let ALL_IMP = prove
(`!P Q l. (!x.
MEM x l /\ P x ==> Q x) /\
ALL P l ==>
ALL Q l`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
REWRITE_TAC[
MEM;
ALL] THEN ASM_MESON_TAC[]);;
let NOT_EX = prove
(`!P l. ~(
EX P l) <=>
ALL (\x. ~(P x)) l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN
ASM_REWRITE_TAC[
EX;
ALL; DE_MORGAN_THM]);;
let NOT_ALL = prove
(`!P l. ~(
ALL P l) <=>
EX (\x. ~(P x)) l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN
ASM_REWRITE_TAC[
EX;
ALL; DE_MORGAN_THM]);;
let MAP_EQ_DEGEN = prove
(`!l f.
ALL (\x. f(x) = x) l ==> (
MAP f l = l)`,
LIST_INDUCT_TAC THEN REWRITE_TAC[
ALL;
MAP;
CONS_11] THEN
REPEAT STRIP_TAC THEN ASM_REWRITE_TAC[] THEN
FIRST_ASSUM MATCH_MP_TAC THEN ASM_REWRITE_TAC[]);;
let ALL_MP = prove
(`!P Q l.
ALL (\x. P x ==> Q x) l /\
ALL P l ==>
ALL Q l`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
REWRITE_TAC[
ALL] THEN ASM_MESON_TAC[]);;
let EX_IMP = prove
(`!P Q l. (!x.
MEM x l /\ P x ==> Q x) /\
EX P l ==>
EX Q l`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
REWRITE_TAC[
MEM;
EX] THEN ASM_MESON_TAC[]);;
let ALL_MEM = prove
(`!P l. (!x.
MEM x l ==> P x) <=>
ALL P l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN REWRITE_TAC[
ALL;
MEM] THEN
ASM_MESON_TAC[]);;
let EXISTS_EX = prove
(`!P l. (?x.
EX (P x) l) <=>
EX (\s. ?x. P x s) l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
EX] THEN
ASM_MESON_TAC[]);;
let FORALL_ALL = prove
(`!P l. (!x.
ALL (P x) l) <=>
ALL (\s. !x. P x s) l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
ALL] THEN
ASM_MESON_TAC[]);;
let MEM_MAP = prove
(`!f y l.
MEM y (
MAP f l) <=> ?x.
MEM x l /\ (y = f x)`,
GEN_TAC THEN GEN_TAC THEN LIST_INDUCT_TAC THEN
ASM_REWRITE_TAC[
MEM;
MAP] THEN MESON_TAC[]);;
let MEM_FILTER = prove
(`!P l x.
MEM x (
FILTER P l) <=> P x /\
MEM x l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
MEM;
FILTER] THEN
GEN_TAC THEN COND_CASES_TAC THEN ASM_REWRITE_TAC[
MEM] THEN
ASM_MESON_TAC[]);;
let EX_MEM = prove
(`!P l. (?x. P x /\
MEM x l) <=>
EX P l`,
GEN_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
EX;
MEM] THEN
ASM_MESON_TAC[]);;
let AND_ALL2 = prove
(`!P Q l m.
ALL2 P l m /\
ALL2 Q l m <=>
ALL2 (\x y. P x y /\ Q x y) l m`,
GEN_TAC THEN GEN_TAC THEN CONV_TAC(ONCE_DEPTH_CONV SYM_CONV) THEN
LIST_INDUCT_TAC THEN LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
ALL2] THEN
REWRITE_TAC[
CONJ_ACI]);;
let INJECTIVE_MAP = prove
(`!f:A->B. (!l m.
MAP f l =
MAP f m ==> l = m) <=>
(!x y. f x = f y ==> x = y)`,
GEN_TAC THEN EQ_TAC THEN DISCH_TAC THENL
[MAP_EVERY X_GEN_TAC [`x:A`; `y:A`] THEN DISCH_TAC THEN
FIRST_X_ASSUM(MP_TAC o SPECL [`[x:A]`; `[y:A]`]) THEN
ASM_REWRITE_TAC[
MAP;
CONS_11];
REPEAT LIST_INDUCT_TAC THEN ASM_SIMP_TAC[
MAP;
NOT_CONS_NIL;
CONS_11] THEN
ASM_MESON_TAC[]]);;
(* ------------------------------------------------------------------------- *)
(* Syntax. *)
(* ------------------------------------------------------------------------- *)
let mk_cons h t =
try let cons = mk_const("CONS",[type_of h,aty]) in
mk_comb(mk_comb(cons,h),t)
with Failure _ -> failwith "mk_cons";;
let mk_list (tms,ty) =
try let nil = mk_const("NIL",[ty,aty]) in
if tms = [] then nil else
let cons = mk_const("CONS",[ty,aty]) in
itlist (mk_binop cons) tms nil
with Failure _ -> failwith "mk_list";;
let mk_flist tms =
try mk_list(tms,type_of(hd tms))
with Failure _ -> failwith "mk_flist";;
(* ------------------------------------------------------------------------- *)
(* Extra monotonicity theorems for inductive definitions. *)
(* ------------------------------------------------------------------------- *)
let MONO_ALL = prove
(`(!x:A. P x ==> Q x) ==>
ALL P l ==>
ALL Q l`,
DISCH_TAC THEN SPEC_TAC(`l:A list`,`l:A list`) THEN
LIST_INDUCT_TAC THEN ASM_REWRITE_TAC[
ALL] THEN ASM_MESON_TAC[]);;
let MONO_ALL2 = prove
(`(!x y. (P:A->B->bool) x y ==> Q x y) ==>
ALL2 P l l' ==>
ALL2 Q l l'`,
DISCH_TAC THEN
SPEC_TAC(`l':B list`,`l':B list`) THEN SPEC_TAC(`l:A list`,`l:A list`) THEN
LIST_INDUCT_TAC THEN REWRITE_TAC[
ALL2_DEF] THEN
GEN_TAC THEN COND_CASES_TAC THEN REWRITE_TAC[] THEN ASM_MESON_TAC[]);;
monotonicity_theorems := [MONO_ALL; MONO_ALL2] @ !monotonicity_theorems;;
(* ------------------------------------------------------------------------- *)
(* Apply a conversion down a list. *)
(* ------------------------------------------------------------------------- *)
let rec LIST_CONV conv tm =
if is_cons tm then
COMB2_CONV (RAND_CONV conv) (LIST_CONV conv) tm
else if fst(dest_const tm) = "NIL" then REFL tm
else failwith "LIST_CONV";;
(* ------------------------------------------------------------------------- *)
(* Type of characters, like the HOL88 "ascii" type. *)
(* ------------------------------------------------------------------------- *)
;
new_type_abbrev("string",`:char list`);;