This file documents changes from version 0 of the Athabasca release.

1. Incremented Globals.version to 1.

2. Addition to phbLib. A new tactic intended to help do proofs by
   contradiction has been added. SPOSE_NOT_TAC takes the current goal, 
   negates it, drives the negation inwards, and then strips the theorem 
   onto the assumption list, leaving the goal "F" (as CCONTR_TAC
   currently does).

3. Renamed phbLib to bossLib.

4. Changed the name of STUFF_TAC in phb/bossLib to STP_TAC. Changed
   old STP_TAC to SIMP_FOL_TAC.

5. Added an extra phase of processing in STP_TAC. Now we simplify as
   much as possible, then we eliminate all the equalities having a
   variable on at least one side (subject to the restriction that the
   variable should not also appear on the other side of the
   equality). This could set up some equations between constructors, in the
   assumptions, so we rewrite any such. This loops until no suitable
   equations with a variable on one side occur in the hypotheses. Finally,
   the finishing tactic is invoked.

6. Added the following standard theorems to boolTheory. These have been 
   moved from Drule and from Jim Grundy's pairLib.

     ABS_SIMP 
     AND1_THM 
     AND2_THM 
     AND_CLAUSES 
     AND_INTRO_THM 
     BETA_THM 
     BOOL_EQ_DISTINCT 
     BOTH_EXISTS_AND_THM 
     BOTH_EXISTS_IMP_THM 
     BOTH_FORALL_IMP_THM 
     BOTH_FORALL_OR_THM 
     COND_CLAUSES 
     COND_ID 
     CONJ_ASSOC 
     CONJ_SYM 
     EQ_CLAUSES 
     EQ_EXT 
     EQ_REFL 
     EQ_SYM 
     EQ_SYM_EQ 
     EQ_TRANS 
     EXCLUDED_MIDDLE 
     EXISTS_OR_THM 
     EXISTS_SIMP 
     FALSITY 
     FORALL_AND_THM 
     FORALL_SIMP 
     F_IMP 
     IMP_CLAUSES 
     IMP_F 
     LEFT_AND_FORALL_THM 
     LEFT_EXISTS_AND_THM 
     LEFT_EXISTS_IMP_THM 
     LEFT_FORALL_IMP_THM 
     LEFT_FORALL_OR_THM 
     LEFT_OR_EXISTS_THM 
     NOT_AND 
     NOT_CLAUSES 
     NOT_EXISTS_THM 
     NOT_F 
     NOT_FORALL_THM 
     OR_CLAUSES 
     OR_ELIM_THM 
     OR_INTRO_THM1 
     OR_INTRO_THM2 
     REFL_CLAUSE 
     RIGHT_AND_FORALL_THM 
     RIGHT_EXISTS_AND_THM 
     RIGHT_EXISTS_IMP_THM 
     RIGHT_FORALL_IMP_THM 
     RIGHT_FORALL_OR_THM 
     RIGHT_OR_EXISTS_THM 
     SELECT_REFL 
     SELECT_UNIQUE 
     TRUTH 

7. Added a theorem asserting the acyclicity of "CONS" to listTheory.

8. Added list_ss to bossLib.

9. Changed SIMP_FOL_TAC in bossLib to check for tautology before starting
   up MESON_TAC. 

10. Deleted pair_thmsTheory in pairLib. Most of the theorems proved there 
    were about "bool" and had nothing to do with pairs, so they have been
    moved to boolTheory (see above). The rest of them have been
    incorporated into pairTheory:

      [CURRY_ONE_ONE_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- (CURRY f = CURRY g) = f = g
      
      [CURRY_UNCURRY_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- !f. CURRY (UNCURRY f) = f
   
      [PEXISTS_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- !P. (?x y. P x y) = ?(x,y). P x y
      
      [PFORALL_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- !P. (!x y. P x y) = !(x,y). P x y
      
      [UNCURRY_CURRY_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- !f. UNCURRY (CURRY f) = f
      
      [UNCURRY_ONE_ONE_THM]
      Theorem
      [oracles: ] [axioms: ] [] |- (UNCURRY f = UNCURRY g) = f = g
      
      [UNCURRY_VAR]
      Theorem
      [oracles: ] [axioms: ] [] |- !f v. UNCURRY f v = f (FST v) (SND v)

11. Moved the theorems proved in the Taut_thms structure to boolTheory. As 
    a result, Taut_thms has been deleted.

12. Deleted "ptm_with_ty" from Q.sml in QLib. It has been moved to Parse
    and renamed "typedTerm":

        typedTerm: term quotation -> hol_type -> term

    parses a term with the type constraint given by the second argument.


13. Augmented the behaviour of Q.SPEC_TAC in response to some 
    unsatisfactory behaviour noticed by Pierre Casteran. 

       Q.SPEC_TAC (q1,q2) : term quotation * term quotation -> tactic

    If q1 is a variable, then find the first free var occurrence with the 
    same name. Use that to get the type with which to parse q2 (which has 
    to be a variable).  If q1 is not a var, then it might be a constant, 
    and the same applies.  Otherwise q1 is a comb or an abs. Look for an 
    exact (aconv) occurrence in the goal, and use the type of that to 
    constrain q2. If there isn't an exact occurrence, look for a matching
    occurrence.


14. The following primitive-but-should-have-been-derived rules

        EXT
        GSUBS
        CONTR
        MK_ABS
        MK_EXISTS
        EQT_INTRO
        IMP_TRANS
        ADD_ASSUM
        SUBST_CONV
        IMP_ANTISYM_RULE
 
   have now been made into bona-fide derived rules. No loss in speed 
   was noticed. The remaining primitive rules comprise the original
   8 rules of the HOL logic, extended by a fairly standard batch 
   of introduction and elimination rules for the logical connectives.


15. Added the basic tactics MK_COMB_TAC and BINOP_TAC, both from John Harrison.
    MK_COMB_TAC reduces 

         ?- f x = g y 
    to 
         ?- f = g  and  ?- x = y.

    BINOP_TAC reduces 

        ?- $op m n = $op p q
    to 
        ?- m = p  and  ?- n = q.


16. Added PAT_ASSUM, an analogue of POP_ASSUM, to Tactical. 

        PAT_ASSUM M ttac

    searches for an assumption that matches (in a first order sense) M,
    and makes the first one to match available to the theorem 
    continuation ttac. It has also been added to QLib.

17. Added platform-sensitivity. The std.prelude script now binds a variable

        archOS : string

   The values assigned to archOS are computed by a shell script "archOS" 
   found in the tools directory.

18. bossLib.SPOSE_NOT_TAC has been deleted and replaced with

        SPOSE_NOT_THEN : (thm -> tactic) -> tactic

   SPOSE_NOT_THEN takes the current goal, negates it, drives the
   negation inwards using higher-order rewrite rules, and then
   applies the thm-tactic. This is more flexible than SPOSE_NOT_TAC.

19. Added

        set_fixity : string -> fixity -> unit

    to Theory. It allows the changing of the parse status of any 
    existing constant, for the current session. If the constant has been
    declared in the current theory, its new parse status will become
    the one that is exported.

20. Added a theory of finite maps due to Graham Collins and Don Syme
    to the sources. It is accessible via

        load "finite_mapTheory";

21. Added Ken Larsen's robdd library.

22. Added Michael Norrish's

      HAVE : term quotation -> tactic -> tactic

    to bossLib, for doing "assertional" style reasoning. See the end of
    examples/euclid.sml for an example.

23. Both HOLDIR and archOS are found in the "Globals" structure. They
    get their values from environment variables.

24. Deleted some hol90-specific bindings from Globals, e.g., `interp'.

25. Some changes have been made to bin/archOS in response to
    installation problems found by Jim Grundy on IRIX.

25. Added 

        dropn : int -> proofs

    to goalstackLib. It allows the dropping of multiple proofs with a 
    single call. 

26. Added two higher-order rewrite rules to pairTheory:

       EXISTS_PROD = (?p. P p) = ?p_1 p_2. P(p_1,p_2)
       FORALL_PROD = (!p. P p) = !p_1 p_2. P(p_1,p_2)

27. Mike Norrish upgraded the "RecordType" package so that it will
    define records with fields of polymorphic type.

28. Documentation for hol-mode can be found in doc/hol-mode. Also moved
    hol98.emacs -- which implements hol-mode -- to tools/hol98.emacs. 
    Both of these are due to Mike Norrish.

29. bossLib.Define now invokes the TFL definition principle when 
    the basic definition principles (including prim. rec. definitions) fail. 
    In non-recursive cases, the constant gets defined and the (vacuous)  
    termination conditions are eliminated. In (non-nested) recursive cases,
    termination conditions are left on the assumptions for the user to 
    eliminate. Nested recursions will fail: use tflLib.Rfunction for them.

30. .... there was a change here but it got revoked.

31. Changed the name of the "int" library to "integer". Also, changed the
    name of "intTheory" to "integerTheory".

32. Moved ABS_REP_THM (proved and used in `Type_def_support') to
    boolTheory. This was to avoid a bug found by Joe Hurd. The problem is
    that compiled code is being executed in a HOL signature augmented from 
    that of compilation time. The effect is that identifiers thought to be
    free were actually being treated as constants. (The real fix is to make
    available a parser that takes a fixed signature as an argument.)

33. Added the "axiom" of dependent choices to prim_recTheory:

         !P R a. 
             P a /\ (!x. P x ==> ?y. P y /\ R x y)
             ==> 
              ?f. (f 0 = a) /\ 
                  !n. P (f n) /\ R (f n) (f (SUC n))

34. Added Joe Hurd's port of John Harrison's "reals" library from
    Hol-Lite. This includes the definition of the reals, various bits of 
    analysis, a real (linear) arithmetic decision procedure, and a theory
    of polynomials.

35. The exception "architecture" of Hol98 has changed, in order 
    to properly sit atop the implementation of exceptions in MoscowML. 
    The MoscowML runtime maps an operating system interrupt into the
    "Interrupt" exception. Thus one can write

        <ML-expression> handle Interrupt => .....

    This does not work well with the LCF/HOL tradition of using exceptions 
    to escape from fruitless proof activities. For example, the usual
    definition of the ORELSE tactical is

        fun (t1 ORELSE t2) g = t1 g handle _ => t2 g

    However if one then defines, as is also usual, 

        fun REPEAT tac g = ((tac THEN REPEAT tac) ORELSE ALL_TAC) g

    there is an immediate problem with looping tactics written with REPEAT, 
    since they can not be broken out of with Interrupt: the interrupt will
    get caught by the "handle _ " of ORELSE. 

    Our solution to this problem is to define ORELSE in terms of HOL_ERR:

        fun (t1 ORELSE t2) g = t1 g handle HOL_ERR _ => t2 g

    This will allow an interrupt raised in the handling of the first
    tactic to propagate to the top level. However, it also means that 
    tactics (and conversions, and in general, any looping
    construct) must be written so as to ensure that, if it raises an 
    exception, then that exception is a HOL_ERR. Furthermore, the practice
    of writing proof procedures in the following style

        fun proof_proc x = 
           let val ....
           in
             <answer>
           end
           handle _ => raise HOL_ERR ...

    is no longer a good idea, since an Interrupt exception raised inside
    proof_proc is trapped and changed into a HOL_ERR.

    Another consequence is that sloppily-written proof procedures that 
    depend on binding or match failures to be caught by a "handle _" will 
    fail in mysterious ways (even in some cases terminating the MoscowML 
    session abruptly). Many, but not all, of the kernel libraries have
    been re-written as a result. If you encounter such strange behaviour 
    in the libraries, please let us know.
      
36. Removed exceptions NOT_FOUND and UNCHANGED from Lib.sml.

37. Added function

       Type.dom_rng : hol_type -> hol_type * hol_type

    which inverts Type.-->, i.e. it returns the domain and range components 
    of a function type.

38. Added function 

       Lib.trye : ('a -> 'b) -> 'a -> 'b

    which applies the first argument to the second and, if any exception is
    raised, makes a HOL_ERR exception and raises it. Useful for coercing
    non-HOL_ERR exceptions to HOL_ERRs, which is important because of point 
    35 above. 

39. The "reduce" library has been changed. The structure "reduceLib" now
    is the only structure that needs to be known to use the library. It
    has the signature

        val NOT_CONV  : conv
        val AND_CONV  : conv
        val OR_CONV   : conv
        val IMP_CONV  : conv
        val BEQ_CONV  : conv
        val COND_CONV : conv
    
        val NEQ_CONV  : conv
        val LT_CONV   : conv
        val GT_CONV   : conv
        val LE_CONV   : conv
        val GE_CONV   : conv
        val SUC_CONV  : conv
        val PRE_CONV  : conv
        val SBC_CONV  : conv
        val ADD_CONV  : conv
        val MUL_CONV  : conv
        val EXP_CONV  : conv
        val DIV_CONV  : conv
        val MOD_CONV  : conv
    
        val RED_CONV    : conv
        val REDUCE_CONV : conv
        val REDUCE_RULE : thm -> thm
        val REDUCE_TAC  : tactic

    The structures "Dest" and "Redconv" have been deleted.

40. Fixed Ho_resolve.MATCH_MP (and the other routines in Ho_resolve)
    to now use higher-order matching. This was a bug inserted when
    I hastily ported the higher-order matching stuff to Hol98 from
    hol90.10.

41. Added 

         Theory.set_MLname : string -> string -> unit

    which allows the internal binding for a definition, axiom, or theorem
    to be changed. For example, sometimes automatic tools build weird 
    names that the user wants to change to something more readable. 

    Example.   set_MLname "#_DEF" "Hash_def";

42. Added the flag

       Globals.priming : string option ref     (* default value = NONE *)

    which allows the style of renaming to avoid variable capture to be
    changed. Currently, renaming of variables is done by attaching primes (')
    to bound variable names. For example,

        beta_conv 
           (Term`(\x y z. y x z z' z'' y' y'') (y z)`);

    gives

        \y''' z'''. y''' (y z) z''' z' z'' y' y''.

    When a lot of renaming has been done, this style can be hard to
    read. Thus another style, where numerical suffixes are used, can also 
    be mandated (by setting "priming" to SOME <string>). For example,

        priming := SOME "";
        beta_conv 
           (Term`(\x y z. y x z z1 z2 y1 y2) (y z)`);

    gives

        \y3 z3. y3 (y z) z3 z1 z2 y1 y2

    Other kinds of suffixes can be used, e.g.,

        priming := SOME "_"

    in which case

        beta_conv 
           (Term`(\x y z. y x z z1 z2 y1 y2) (y z)`);
    gives

        \y_1 z_1. y_1 (y z) z_1 z1 z2 y1 y2.

    It is not checked whether the resulting bound variables are lexically 
    well-formed. That is, one could perform

        priming := SOME "#";
        beta_conv 
           (Term`(\x y z. y x z z1 z2 y1 y2) (y z)`);

    and get

        \y#1 z#1. y#1 (y z) z#1 z1 z2 y1 y2

    which is not accepted by the Hol98 parser.



43. Added

        bossLib.Define_suffix : (string -> string) ref

    which controls how the automatically computed ML binding is built.
    The default value is

        fn s => s^"_def"

    Example.  

         Define `K x y = x`;

    will add the definition to the current theory under the name "K_def".

44. Added the following conversionals

       FORK_CONV   : conv * conv -> conv 
       BINOP_CONV  : conv -> conv
       QUANT_CONV  : conv -> conv
       BINDER_CONV : conv -> conv

    to Conv.

    * FORK_CONV applies its two argument conversions to the two operands of a
      binary operator, i.e.,

              c1 N = |- N = N'     c2 P = |- P = P'
      ---------------------------------------------------
          FORK_CONV (c1, c2) (M N P) = |- M N P = M N' P'

      The operator (M above) is not examined, i.e., it is not checked to see 
      that it is a constant for example. 

    * BINOP_CONV just calls FORK_CONV with the same conversion in each
      slot:

        fun BINOP_CONV c = FORK_CONV (c,c)

    * QUANT_CONV applies its argument conversion to the body of a non-lambda
      binding.

                              c N = |- N = N'
        -----------------------------------------------------
         QUANT_CONV c (M (\v. N)) = |- M (\v. N) = M (\v. N')

     * BINDER_CONV applies its argument conversion to the body of a 
       lambda binding or a non-lambda binding.

           fun BINDER_CONV conv = ABS_CONV conv ORELSEC QUANT_CONV conv
   
45. Changed the name of the infix operator that combines relations 
    lexicographically to "LEX".

46. Sped up Conv.EXISTS_OR_CONV. The specification is

      "A call to EXISTS_OR_CONV "?x. P \/ Q"  returns:

           |- (?x. P \/ Q) = (?x.P) \/ (?x.Q)"

    The original worked by deriving the appropriate instance
    of the higher-order rewrite rule boolTheory.EXISTS_OR_THM:

        |- !P Q. (?x. P x \/ Q x) = (?x.P x) \/ (?x.Q x).

    The new version works by instantiating the higher-order rewrite rule, 
    and is nearly 50% faster. 

    Many of the conversions in Conv.sml could be similarly sped up, and 
    the optimization seems mechanizable. It would be an interesting bit
    of research to 
    
        0. Investigate ways to compile these higher-order rewrites to 
           efficient conversions.

        1. Compare the speed-up w.r.t. to using a higher-order rewriter.

47. The structure "Datatype" provides a high-level interface to datatype
    definitions in HOL. Actually, there are a couple of interfaces. The
    first is functional (although it side-effects the current theory
    when it defines the type and some related functions).

       val primHol_datatype : factBase -> term quotation -> tyinfo

    Example. 

        val dBinfo =
           primHol_datatype (theFactBase())
                `dB = Var  of 'a
                    | Bvar of num
                    | Comb of dB => dB
                    | Abs  of dB`

    The second is imperative:  it side-effects the current
    theory and also adds the results from the definition to
    `theFactBase', a database used by bossLib.  "theFactBase" has
    operations for adding and finding information in it.

       val theFactBase  : unit -> factBase
       val add          : tyinfo -> unit
       val get          : string -> tyinfo option

    The imperative datatype definition entrypoint -- which is also made
    available in bossLib -- is

        val Hol_datatype : term quotation -> unit

    Example (again). 

        val () = Hol_datatype 
                  `dB = Var  of 'a
                      | Bvar of num
                      | Comb of dB => dB
                      | Abs  of dB`

    A "factBase" is a set of facts about datatypes that have been
    defined. Elements of the set can be manipulated with functions from
    the structure "Facts" :

        mk_facts : {datatype_ax:thm,
                    case_def: thm,
                    one_one : thm option,
                    distinct: thm option} -> tyinfo
 
        (* Extraction functions *)
        ty_name_of      :tyinfo -> string
        axiom_of        :tyinfo -> thm
        constructors_of :tyinfo -> term list
        case_const_of   :tyinfo -> term
        case_cong_of    :tyinfo -> thm
        case_def_of     :tyinfo -> thm
        induction_of    :tyinfo -> thm
        nchotomy_of     :tyinfo -> thm
        distinct_of     :tyinfo -> thm option
        one_one_of      :tyinfo -> thm option
        simpls_of       :tyinfo -> thm list
        size_of         :tyinfo -> (term * thm) option
 
        (* Overwriting parts of a tyinfo object (functional) *)
        put_nchotomy  : thm -> tyinfo -> tyinfo
        put_induction : thm -> tyinfo -> tyinfo
        put_simpls    : thm list -> tyinfo -> tyinfo
        put_size      : term * thm -> tyinfo -> tyinfo
 
        (* tyinfo sets and operations *)
        empty : factBase
        add   : factBase -> tyinfo -> factBase
        get   : factBase -> string -> tyinfo option
        elts  : factBase -> tyinfo list

    A recent addition to the information computed from a datatype
    definition is a definition of the size of elements of that
    type. Generally, the size of a datatype element is one plus the size
    of any subelements. Leaf elements have size zero, as do any elements
    of unknown datatypes. Functional types are (intentionally) unknown
    and so have size zero as well. The size function for a parameterized
    type will be parameterized by functions for the size of argument
    types.

    Example (continued).
        - Facts.size_of dBinfo;
        > val it =
           SOME(``dB_size``,
            |- (!f x. dB_size f (Var x) = 1 + f x) /\
               (!f n. dB_size f (Bvar n) = 1 + I n) /\
               (!f d2 d1. dB_size f (Comb d1 d2) 
                          = 1 + dB_size f d1 + dB_size f d2) /\
               (!f d. dB_size f (Abs d) = 1 + dB_size f d))


    The Datatype structure also provides a function that takes an HOL
    type and returns an object-language function that gives the size of
    an object of that type.

        type_size : factBase -> hol_type -> term 

    Example (continued).
        - type_size (theFactBase())  ``:(num # 'a) list dB``
        > val it = 
           ``dB_size (list_size ((\f g (x,y). f x + g y) I (\v. 0)))``

    This example is somewhat fanciful, and the result could be
    simplified, but it should get the idea across. The results of
    type_size are used in bossLib to support automatic synthesis of
    termination measures for recursive functions.


    Notes.
    ------
    * When "Datatype" is first loaded, it already knows about the
      datatypes bool, prod, num, option, and list.

    * Only "normal" datatypes are maintained in theFactBase. Records,
      quotients, and mutual/nested recursive types need to be handled
      manually, i.e., as before. This should eventually change so that
      there is a single entrypoint for defining types.

48. The structures "TheFactBase", "Btree", "stdFactBase", and
    "Holdatatype" have been removed from src/datatype.

49. (superseding 29) "bossLib.Define" now makes an attempt at being a
    "one-stop" way of defining functions. It will define non-recursive
    and primitive recursive functions and attempt to define recursive
    (but not prim. rec) functions. For these more difficult recursions,
    it attempts to find a measure under which recursive calls become
    smaller (and to prove that they do indeed become
    smaller). Currently, it examines the domain type of the function
    being defined and synthesizes a "size" measure.  Then it does some
    basic simplifications and then attempts to use the linear arithmetic
    package to prove the termination constraints.  If this termination
    proof fails, then the termination constraints remain on the
    hypotheses. Nested recursive functions will be rejected by "Define".

    Examples.

    1. Define 
        `(gcd 0 y = y)  /\
         (gcd (SUC x) 0 = SUC x) /\
         (gcd (SUC x) (SUC y) = 
            (y<=x => gcd (x-y)   (SUC y) 
                  |  gcd (SUC x) (y-x)))`;

       proves all termination conditions and gives 
       
           |- ((gcd 0 y = y) /\
               (gcd (SUC x) 0 = SUC x) /\
               (gcd (SUC x) (SUC y) =
                   ((y <= x) => (gcd (x - y) (SUC y)) 
                             |  (gcd (SUC x) (y - x))))) 
               /\  (* induction theorem *)
              !P.
                 (!y. P 0 y) /\
                 (!x. P (SUC x) 0) /\
                 (!x y. (~(y <= x) ==> P (SUC x) (y - x)) /\
                          (y <= x  ==> P (x - y) (SUC y))
                        ==> P (SUC x) (SUC y))
                 ==>
                   !v v1. P v v1

    2. Define
        `(Tot [] = 0) /\
         (Tot (CONS 0 t) = Tot t) /\
         (Tot (CONS n t) = 1 + Tot (CONS (n-1) t))`;

       gives (note that it can be further simplified)

           |- ((Tot [] = 0) /\
               (Tot (CONS 0 t) = Tot t) /\
               (Tot (CONS (SUC v2) t) = 1 + Tot (CONS (SUC v2 - 1) t)))
              /\
             !P.
                 P [] /\
                 (!t. P t ==> P (CONS 0 t)) /\
                 (!v2 t. P (CONS (SUC v2 - 1) t) ==> P (CONS (SUC v2) t)) 
                 ==>
                   !v. P v

    3. Define
        `(filter P [] = []) /\
         (filter P (CONS h t) = (P h => CONS h (filter P t) | filter P t))`;

       Define
        `(qsort(ord, []) = []) /\
         (qsort(ord, CONS x rst) = 
            APPEND (qsort(ord, filter($~ o ord x) rst))
                   (CONS x (qsort(ord, filter(ord x) rst))))`;

       gives (note that `filter' is primitive recursive and has no
       induction theorem as a result):
    
           |- (!P. filter P [] = []) /\
              (!P t h. filter P (CONS h t) = 
                          (P h => CONS h (filter P t) 
                                 | filter P t))

       and

       <<HOL message: "qsort" defined: side-conditions remain in hypotheses.>>

          [oracles: #] [axioms: ] [...]
          |- ((qsort (ord,[]) = []) /\
              (qsort (ord,CONS x rst) =
                  APPEND (qsort (ord,filter (~ o ord x) rst))
                         (CONS x (qsort (ord,filter (ord x) rst)))))
             /\
              !P. (!ord. P (ord,[])) /\
                  (!ord x rst.
                      P (ord,filter (ord x) rst) /\ 
                      P (ord,filter (~ o ord x) rst) ==> P (ord,CONS x rst))
                   ==>
                     !v v1. P (v,v1)

       The side conditions are:

           [``WF R``, 
            ``!ord x rst. R (ord,filter (ord x) rst) (ord,CONS x rst)``,
            ``!ord x rst. R (ord,filter (~ o ord x) rst) (ord,CONS x rst)``]

       and it is up to the user to perform the termination proof. The
       "size" measure is still appropriate for the wellfound relation R
       in the side conditions and can be generated by

          type_size (theFactBase()) (Type`:('a -> 'a -> bool) # 'a list`);

   More powerful termination methods are known, e.g. Walther recursion
   (and extensions thereof). These can usually prove the
   termination of functions like "qsort" and should be implemented.

50. Added ETA_THM to boolTheory:

       |- !M. (\x. M x) = M

51. Renamed the structure `Simplifier' to `simpLib', in order to get around a
    MoscowML bug (having to do with constructors in signatures).

52. Added 

       Type.type_compare : hol_type -> hol_type -> order
       Term.term_compare : term -> term -> order

    These make the existing type and term orderings easily usable by 
    datastructures that depend on "order" for
    efficiency. Alpha-convertible terms return EQUAL under term_compare.

53. Added 

        Tactic.NTAC : int -> tactic -> tactic

    which takes a number "n" and a tactic and applies the tactic n times.

        fun NTAC n tac = funpow n (curry op THEN tac) ALL_TAC

54. Revised bossLib so that it supplies

       Cases  : tactic
       Induct : tactic

       Cases_on  : term quotation -> tactic
       Induct_on : term quotation -> tactic

     The first two work with the leading universally quantified variable
     in the goal, and perform a case split or induction,
     respectively. The latter two take a term as an argument, and the
     functions will attempt to locate the term in the goal (either the
     assumptions or the conclusion) and then perform a case split or
     induction. If the given term ("M" say) is not a variable, a new
     variable "v" not already occurring in the goal is created, and used
     to build a term "v = M" which the goal is made conditional on
     before the induction is performed. First however, all terms
     containing free variables from M are moved from the assumptions
     to the conclusion of the goal, and all free variables of "M" are
     universally quantified.

55. Removed a deep-seated irritant in arithSimps. Now "SUC x" will not
    get replaced by "x+1" by default. If the user wishes that, then 
    arithmeticTheory.ADD1 should be added into the simpset.

56. Added an (adhoc) bunch of rewrite rules to bossLib.arith_ss. These
    boost the power of arith_ss considerably. Notice that the rewrites
    coming from recursive definitions are not added by default (using them
    in an uncontrolled fashion seemed to make some proofs more difficult).

57. The look-and-feel of the goalstack has changed to be less
    cluttered. The main change is that quotes are no longer attached to
    the terms in a goal. The hypotheses are now numbered, although no
    proof routines currently make use of these numbers. (And it's not clear
    that any should, judging by past experience. The hypotheses are 
    notionally a set.)

58. bossLib.HAVE has been changed to 

        bossLib.by : term quotation * tactic -> tactic.

    "by" is an infix of high priority (currently 8) and it is used,
    e.g.,

        `P /\ ~Q x y` by <tactic>.

    When bossLib is loaded and opened, the infixity of "by" must be
    re-asserted.

59. Added a fix to the install script to make bin/hol and
    bin/hol.enquote get written properly at installation time. Louise
    Dennis found the bug (on SUNOS 5.5.1) and Mike Norrish provided the fix. 

60. Re-added a version of the BDD library. (Next time I won't lose it.)
    It supplies two main structures: Robdd and robddLib. The first
    provides an ML interface to the BuDDy C library. The second builds
    on the first to provide a fast HOL tautology checker (and more).

61. Changed RES_TAC, to fix a bug noticed by DAISAKU Asanuma. Apparently, 
    the version in hol90 was ported from hol88 before the last bugfix to
    the hol88 version.  This bugfix has now been propagated. This fix
    has the potential to break some old proofs, although none were
    broken when the Hol98 system was rebuilt with the fix.

62. Replaced the ML-Yacc based parser for raw terms by a hand-written parser.
    This change should be invisible to the user.

63. Replaced the ML-Yacc based parser for HOL types by a hand-written version.
    This change is almost invisible to users. First, there should be better
    error messages when parsing fails. Second, the type of the type
    parsers has changed. Heretofore, the type of the parser was 

        Type : term quotation -> hol_type

    Now it is 

        Type : hol_type quotation -> hol_type

    One consequence of this change is that a type can be antiquoted into
    another more easily than before, where one had to first wrap the 
    "ty_antiq" constructor around the type being inserted, thus taking a
    totally useless detour through the type of terms.

64. There is now a type of "pretype", which is analogous to the type 
    of preterms: the type parser generates an element of this type, and 
    a subsequent translation is made to produce elements of type `hol_type'.

65. The "empty string" constant in stringTheory has been named 
    "emptystring", instead of "\"\"". Users should not notice this change,
    since the surface syntax is unchanged.

66. Replaced the ML-Yacc based parser for datatype specifications by a
    hand-written version.

67. Changed the name of the "nested_rec" library to "nestrec", out of sheer
    cussedness.

68. Added Peter Homeier's "mutual" library. This provides a nice
    wrapper for the functionality provided by the "mutrec" and "nestrec"
    libraries. It provides a concrete syntax describing types, 
    improved support for defining functions, and improved support for 
    doing structual induction over such types. For example, now the
    following syntax can be used to define a mutual and nested datatype.

          mutualLib.define_type 
               [listTheory.list_Axiom, pairTheory.pair_Axiom]

             `command = Assignment of num list # expression list
                      | Sequence of command list;
   
           expression = Numeral of num
                      | Plus of expression # expression
                      | Valof of command`;

     Many examples can be found in src/datatype/mutual/examples, and
     Peter's paper in the participants proceedings of TPHOLs98 explains
     the functionality of the library quite well.

69. Changed the name of bin/install to bin/configure to more accurately
    fit its function.

70. Added a simple database, which contains all the theorems,
    definitions, and axioms found in the ancestry of the current theory.
    When a theory is loaded, all its objects are automatically loaded
    into the database. Objects in the database can be accessed by name
    or by pattern. The database is accessed through the `DB' structure 
    with the following entrypoints:

       datatype class = Def | Axm | Thm
       type data = (string * string) * (thm * class)

       val lemmas : unit -> (string * string, data) Binarymap.dict
       val thy    : string -> data list
       val facts  : string -> data list
       val match  : string list -> Term.term -> data list (* first order *)
       val rawmatch  : (term -> term -> 'a)
                       -> string list -> Term.term -> data list

    The type `data' has four slots: the first is the theory name, the
    second is the binding name, the third is the theorem, and the fourth
    is the classification of the theorem (axiom, theorem, or definition).

    `lemmas ()' returns the database. The operations provided by
    the ML library structure Binarymap can be used to manipulate it.

    `thy s' traverses the database; any entries that have a theory slot
    in which s occurs are collected. The case of "s" is not important. 

    `find s' traverses the database; any entries that have a binding
    name in which s occurs are collected. The case of "s" is not
    important.

    `match strl pat' collects all the theories named in strl, and
    attempts to find a matching occurrence of pat anywhere in any
    theorem in that theory. If strl is empty, all theories are
    considered.

    `rawmatch' is just `match' abstracted over the matcher used. This
    allows the use of bespoke matchers for specialized searching. For
    example, one might want to do matching modulo an equational theory.

    Example. (with bossLib loaded)
    ------------------------------

    Suppose we are looking for all induction theorems in the current
    context. Then the following request gets us a long way:

      DB.match [] (Term `Q ==> !x. P x`);

    The request gives:

    [(("arithmetic", "COMPLETE_INDUCTION"),
      (|- !P. (!n. (!m. m < n ==> P m) ==> P n) ==> (!n. P n), DB.Thm)),
     (("bool", "RIGHT_FORALL_IMP_THM"),
      (|- !P Q. (!x. P ==> Q x) = P ==> (!x. Q x), DB.Thm)),
     (("list", "list_INDUCT"),
      (|- !P. P [] /\ (!t. P t ==> (!h. P (CONS h t))) ==> (!l. P l), DB.Thm)),
     (("ltree", "ltree_Induct"),
      (|- !P. (!t. EVERY P t ==> (!h. P (Node h t))) ==> (!l. P l), DB.Thm)),
     (("num", "INDUCTION"),
      (|- !P. P 0 /\ (!n. P n ==> P (SUC n)) ==> (!n. P n), DB.Thm)),
     (("option", "option_induction"),
      (|- !P. P NONE /\ (!x. P (SOME x)) ==> (!o'. P o'), DB.Thm)),
     (("pair", "pair_induction"),
      (|- (!p_1 p_2. P (p_1,p_2)) ==> (!p. P p), DB.Thm)),
     (("primWF", "WF_INDUCTION_THM"),
      (|- !R. WF R ==> (!P. (!x. (!y. R y x ==> P y) ==> P x) ==> (!x. P x)),
       DB.Thm)),
     (("tree", "tree_Induct"),
      (|- !P. (!tl. EVERY P tl ==> P (node tl)) ==> (!t. P t), DB.Thm))]
      : ((string * string) * (Thm.thm * DB.class)) list

     The search has quickly yielded useful information, which could only
     otherwise have been found by laborious use of the help system. 

     Example.

       DB.find "plus";

     returns 

      [(("arithmetic", "MOD_PLUS"),
        (|- !n. 0 < n ==> (!j k. (j MOD n + k MOD n) MOD n = (j + k) MOD n),
       Thm)),
       (("arithmetic", "SUB_PLUS"), (|- !a b c. a - (b + c) = (a - b) - c, 
       Thm))]

    
71. Improved the ARITH_ss by adding a bunch of new theorems to it. These had
    formerly been in bossLib.arith_ss, but Michael Norrish pointed out that
    there should be a trickle-down effect.

72. Changed prim_export_theory, which exports the current theory, to
    have a wacky type. The intent was to have a more "declarative" 
    primitive operation for exporting the theory.

73. Added adjoin_to_theory,

       type thy_addon = {sig_ps    : (ppstream -> unit) option,
                         struct_ps : (ppstream -> unit) option}

       val adjoin_to_theory : thy_addon -> unit

    by which one can request that pieces of ML (represented by
    prettyprinters) be appended to the signature and structure
    representing the current theory when it is exported.
    Requests are serviced in the order that they are made. If the theory 
    is restarted, any pending requests are deleted.

74. Datatype.primHol_datatype (and thus Datatype.Hol_datatype and
    bossLib.Hol_datatype) use the facilities in 73 to make the entries
    in TypeBase transparently persistent. Suppose one exports a theory
    in which a logical type has been defined using one of the Hol_datatype
    entrypoints. Upon loading that theory in a later session, the
    relevant facts will be automatically incorporated into TypeBase.

75. Revision to FactBase (from 49). it's been renamed
    "TypeBase". There's now a prettyprinter for elements of 
     type `tyinfo':

   TypeBase.elts();   (* bossLib loaded *)
   > val it =
    [-----------------------
     -----------------------
     HOL datatype: "bool"
     Characterization: |- !e0 e1. ?!fn. (fn T = e0) /\ (fn F = e1)
     Case analysis:
      |- (!x y. bool_case x y T = x) /\ (!x y. bool_case x y F = y)
     Size: bool_case 0 0
     Induction: |- !P. P T /\ P F ==> (!b. P b)
     Case completeness: |- !b. (b = T) \/ (b = F)
     Distinctness: |- ~(T = F),
     -----------------------
     -----------------------
     HOL datatype: "list"
     Characterization:
      |- !x f. ?!fn1. (fn1 [] = x) /\ (!h t. fn1 (CONS h t) = f (fn1 t) h t)
     Case analysis:
      |- (!b f. list_case b f [] = b) /\
         (!b f h t. list_case b f (CONS h t) = f h t)
     Size:
      |- (!f. list_size f [] = 0) /\
         (!f t h. list_size f (CONS h t) = 1 + f h + list_size f t)
     Induction: |- !P. P [] /\ (!t. P t ==> (!h. P (CONS h t))) ==> (!l. P l)
     Case completeness: |- !l. (l = []) \/ (?t h. l = CONS h t)
     One-to-one: |- !h t h' t'. (CONS h t = CONS h' t') = (h = h') /\ (t = t')
     Distinctness: |- !t h. ~([] = CONS h t),
     -----------------------
     -----------------------
     HOL datatype: "num"
     Characterization:
      |- !e f. ?!fn1. (fn1 0 = e) /\ (!n. fn1 (SUC n) = f (fn1 n) n)
     Case analysis:
      |- (!b f. num_case b f 0 = b) /\ (!b f n. num_case b f (SUC n) = f n)
     Size: \x. x
     Induction: |- !P. P 0 /\ (!n. P n ==> P (SUC n)) ==> (!n. P n)
     Case completeness: |- !m. (m = 0) \/ (?n. m = SUC n)
     One-to-one: |- !m n. (SUC m = SUC n) = m = n
     Distinctness: |- !n. ~(SUC n = 0),
     -----------------------
     -----------------------
     HOL datatype: "option"
     Characterization: |- !f e. ?!fn. (!x. fn (SOME x) = f x) /\ (fn NONE = e)
     Case analysis:
      |- (!u f. option_CASE u f NONE = u) /\
         (!u f x. option_CASE u f (SOME x) = f x)
     Size: \f. option_CASE 0 (\x. 1 + f x)
     Induction: |- !P. (!x. P (SOME x)) /\ P NONE ==> (!o'. P o')
     Case completeness: |- !opt. (?x. opt = SOME x) \/ (opt = NONE)
     One-to-one: |- !x x'. (SOME x = SOME x') = x = x'
     Distinctness: |- !x. ~(NONE = SOME x),
     -----------------------
     -----------------------
     HOL datatype: "prod"
     Characterization: |- !f. ?!fn. !x y. fn (x,y) = f x y
     Case analysis: |- pair_case f (x,y) = f x y
     Size: \f g (x,y). f x + g y
     Induction: |- !P. (!x y. P (x,y)) ==> (!p. P p)
     Case completeness: |- !p. ?x y. p = (x,y)
     One-to-one: |- !x y a b. ((x,y) = (a,b)) = (x = a) /\ (y = b)]
    : TypeBase.tyinfo list


76. Added completeInduct_on and measureInduct_on to bossLib. These allow
    easy invocation of complete induction and measure induction. 

77. Deleted pair_caseTheory, by moving the definition of PAIR_CASE to 
    pairTheory. PAIR_CASE has also been lower-cased to pair_case.

78. The robdd library now builds on Solaris.

79. Fixed a bug in Ho_resolve.HIGHER_REWRITE_CONV. It was raising a
    non-HOL_ERR (when it took the head of an empty list internally).
    This had the effect that it couldn't be joined (via ORELSEC) with
    any other conversion.

80. Added Tactic.WEAKEN_TAC, which inverts ADD_ASSUM. It is useful 
    for eliminating useless hypotheses in tactic proofs. Its definition
    is simple:

       fun WEAKEN_TAC P :tactic = 
         fn (asl,w) => 
           let fun robustP x = Lib.trye P x handle HOL_ERR _ => false
               val (tm,rst) = Lib.pluck robustP asl handle HOL_ERR _
                 => raise TACTIC_ERR "WEAKEN_TAC" 
                       "no matching item found in hypotheses"
           in
             ([(rst,w)], fn [th] => ADD_ASSUM tm th)
           end;

81. Added an extensive theory of finite and infinite multisets from
    Michael Norrish. It is accessible via

       load "bagTheory";

82. Fixed a performance bug in ARITH_CONV, thanks to advice from John
    Harrison. Now the problem

       x1 <= m1 /\ 
       x2 <= (m1 - x1) + y1
       ==>
        ((m1 - (x1 + (x2 - y1))) + (y1 - x2) + y2 
         =
         (((m1 - x1) + y1) - x2) + y2)

    (from Tobias Nipkow) gets solved in finite time, although 
    the proof still takes far too long. The fix has not yet been 
    propagated to the linear arithmetic procedure used in decisionLib.

83. Upgraded the release number to 3.

84. Removed dependence on "ed" (the standard Unix text editor) from 
    the build sequence.

85. Massive changes to the way the system builds, in order to prepare
    for the non-Unix world. Almost all the shell scripts and Makefiles
    that the system used to have are gone or have been rewritten as
    ML executables. Michael Norrish rewrote Holmake in ML - no more
    dependence on GNU make!

     New.   bin/build           (builds the system)
            tools/Holmake       (all source needed to build Holmake)
            tools/configure.sml (ML version of previous configuration stuff)
            tools/Globals.src

     Gone.  <holdir>/Makefile 
            bin/Holmake.enquote  (functionality incorporated in bin/Holmake)
            bin/holdep               ""
            bin/cutdeps              ""
            bin/{camlrunm,mosml,mosmlc,mosmlc.enquote}  (unnecessary)
            tools/Holmake.enquote.src
            tools/Holmake.src
            tools/Holmakefile
            tools/INCLUDE.mk
            tools/Makefile.dbase.src   (moved to <holdir>/help)
            tools/Makefile.src
            tools/archOS
            tools/holdep               (incorporated in tools/Holmake *)
            tools/mosmlc.enquote.src

     Renamed.

             bin/hol.enquote --> bin/hol.unquote
     src/list/ListScript.sml --> src/list/rich_listScript.sml
  src/simp/src/ListSimps.sml --> src/simp/src/rich_listSimps.sml
                  ListTheory --> rich_listTheory

      The former ListScript.sml and ListTheory.* have had to be renamed
      since some OS's are not sensitive to case distinctions; these
      would consider listTheory and ListTheory to be the
      same. Therefore, ListTheory is now renamed to
      rich_listTheory. This has consequences for the names of the
      simplification sets for ListTheory (rich_list) in src/simp/

86. Massive changes to accomodate Norrish numerals.  The theory hierarchy
    has been reorganized, so that wellfoundedness could be a parent of 
    numbers.

    Gotchas: ZERO is now a constant defined in numTheory.
           : TC is a constant defined in TCTheory

    As well as the new representation for values of type ``:num``, the
    code for numerals has resulted in the addition of an implementation
    of arbitrary precision natural numbers and integers.  These are
    arbnum and arbint respectively, and currently live in src/portableML.  

    There is now a {dest_,mk_,is_}numeral in Term.sig which does the right
    thing.  The range of the first and the domain of the second is
    arbnum.num. 

    In general, the change has resulted in both efficiency and scope
    improvements.  For example, 

       x < 12000000 * 2 ==> x < 24000009 

    is within the scope of the current arithmetic packages but the
    necessarily poor performance of multiplication makes it pragmatically
    impossible. 

    Of course, the procedures also now cope with values are too big for
    the old packages and which would have caused Overflow exceptions.

    Changes specific to each package:

    ARITH_CONV:
     Uniform replacement of ints with arbints.  In .sig files each now
     starts with "local type int = arbint.int in".  In .sml files, each
     now starts with "open arbint  val << = String.<   infix <<"  The
     latter two declarations are to provide a string comparison function,
     which was hitherto available just with <.  

     term_of_int and int_of_term are now defined in terms of mk_numeral
     and dest_numeral respectively. 

     Various convs that duplicate code from reduceLib have been removed.
     FAST_MULT_CONV still does caching of its results, but just calls
     reduceLib.MUL_CONV. 
 
    decision:
      Thanks to Richard's use of a NumType module, this switch is very
      easy.  This module is re-implemented to use arbints.  

    RealArith.sml:
      Again, all integers are replaced with arbints.  Where integers are
      result of built-in procedures such as length, I inject them into
      arbints with arbint.fromInt.  I am slightly worried that some of
      this may have been unnecessary as integers are often no more than
      indices into lists, and it's not clear whether these lists are
      supposed to be arbitrarily long.  

87. 
