app load ["bossLib", "Q"];
open bossLib;
infix 8 by;


(*---------------------------------------------------------------------------
            An APL-style "iota" function.
 ---------------------------------------------------------------------------*)

val iota_def = 
  Hol_defn "iota" 
           `iota bot top = if bot > top then [] else bot::iota (bot+1) top`;


val (iota_eqn, iota_ind) =
TotalDefn.tprove 
 (iota_def,
  WF_REL_TAC iota_def `measure \(b,t). SUC t - b` 
    THEN DECIDE_TAC);


(*---------------------------------------------------------------------------*
 * A couple of properties.                                                   *
 *---------------------------------------------------------------------------*)

val iota_bounds = Q.prove
(`!bot top n. MEM n (iota bot top) ==> bot <= n /\ n <= top`,
 recInduct iota_ind
  THEN REPEAT GEN_TAC THEN NTAC 2 STRIP_TAC
  THEN ONCE_REWRITE_TAC [iota_eqn]
  THEN RW_TAC list_ss [listTheory.MEM]
  THENL [DECIDE_TAC, 
         DECIDE_TAC, 
         PROVE_TAC [DECIDE `x+y <= z ==> x<=z`],
         PROVE_TAC[]]);


val iota_length = Q.prove
(`!bot top. bot <= top ==> (LENGTH(iota bot top) = (top-bot)+1)`,
 recInduct iota_ind
  THEN REPEAT GEN_TAC THEN NTAC 2 STRIP_TAC
  THEN ONCE_REWRITE_TAC [iota_eqn]
  THEN RW_TAC std_ss [listTheory.LENGTH]
  THENL [DECIDE_TAC,
         RW_TAC std_ss [arithmeticTheory.ONE,arithmeticTheory.ADD_CLAUSES] 
           THEN RW_TAC std_ss [arithmeticTheory.ADD1] THEN
           Cases_on `bot = top` THENL 
            [RW_TAC std_ss [] 
               THEN ONCE_REWRITE_TAC [iota_eqn] THEN RW_TAC list_ss [],
             `bot+1 <= top` by DECIDE_TAC THEN
             `LENGTH (iota (bot+1) top) = (top - (bot+1)) + 1` by RES_TAC
               THEN Q.PAT_ASSUM `x = y` SUBST_ALL_TAC
               THEN WEAKEN_TAC(fn tm => is_imp tm andalso not(is_neg tm))
               THEN DECIDE_TAC]]);

(*---------------------------------------------------------------------------
      Some computations with iota.
 ---------------------------------------------------------------------------*)

local open computeLib
      val compset = bossLib.initial_rws()
      val _ = add_thms [iota_eqn] compset
in
val Eval = Count.apply (CBV_CONV compset) o Term
end;

Eval `iota 0 0`;
Eval `iota 0 12`;
Eval `iota 12 10`;
Eval `iota 12 100`;
Eval `iota 250 351`;
Eval `iota 0 1000`;
