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 were 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 real, 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 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 operator that combines relations 
    lexicographically from "X" to "**".

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.

    * The effect of a Hol_datatype invocation is not persistent. Suppose
      a datatype is defined in "xTheory" by invoking
      Datatype.Hol_datatype. In a descendant theory of xTheory, the
      information about the type must be re-created and re-stored in
      theFactBase. The function "Facts.mk_facts" may be used for this,
      but it will be clumsy. Eventually, such information will be
      persistent.

    * 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 add
    arithmeticTheory.ADD1 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. 
