From tfm%computer-lab.cambridge.ac.uk@NSFnet-Relay.AC.UK  Thu Apr 12 12:29:25 1990
Received: by iris.ucdavis.edu (5.57/UCD.EECS.2.0)
        id AA00234; Thu, 12 Apr 90 12:29:25 PDT
Received: from ucdavis.ucdavis.edu by clover.ucdavis.edu (5.59/UCD.EECS.1.11)
        id AA18266; Thu, 12 Apr 90 12:33:49 PDT
Received: from NSFNET-RELAY.AC.UK by ucdavis.ucdavis.edu (5.61/UCD2.03)
        id AA12366; Thu, 12 Apr 90 12:28:03 -0700
Received: from sun.nsfnet-relay.ac.uk by vax.NSFnet-Relay.AC.UK
           via Janet with NIFTP  id aa28049; 12 Apr 90 20:15 BST
Received: from moorhen.cl.cam.ac.uk by gnnt.Cl.Cam.AC.UK id aa16516;
          12 Apr 90 20:16 BST
Received: by uk.ac.cam.cl.moorhen (4.0/SMI-3.0DEV3)
        id AA00819; Thu, 12 Apr 90 20:16:45 BST
Date: Thu, 12 Apr 90 20:16:45 BST
From: tfm%computer-lab.cambridge.ac.uk@NSFnet-Relay.AC.UK
Message-Id: <9004121916.AA00819@uk.ac.cam.cl.moorhen>
To: info-hol%clover.ucdavis.edu@NSFnet-Relay.AC.UK
Subject: Some remarks on REWRITE_TAC in answer to the question.

In a recent message, Dave Barker-Plummer asks the following
questions about rewriting in HOL:

+ ---------------------------------------------------------------------
|  1.  What does the prefix ONCE_ mean in ONCE_REWRITE_TAC?
|      I observe that ONCE_REWRITE_TAC is implemented in terms of
|      ONCE_DEPTH_CONV whose documentation says that it applies only to
|      the first term on which it succeeds, but this does not seem to be
|      true.
|
|  2.  How is an instantiated version of the theorem converted into a
|      more general rewrite rule?  That is, how does (PAIR x y) = e
|      rewrite (PAIR y x) when x and y are not variables.
|
|  3.  Why does the behaviour of ASM_REWRITE_TAC[]
|      when the assumption list has a single member t, differ from the
|      behaviour of REWRITE_TAC[t] when the assumption list is empty.
+ ---------------------------------------------------------------------

The full story about rewriting is given in the REFERENCE manual, so I won't go
into the details here.  But here are some brief answers to these questions,
which I hope may be helpful.

1: The prefix ONCE_ means that the rewrite rules are, first of all,
   applied only once, rather than several times.  Second, the sub-terms
   that get rewritten are ALL those subterms found using a top-down
   breadth-first (as it were) search of the term to be rewritten.
   For example, if we have the rewrite rule x+y --> y+x, i.e:

        ONCE_REWRITE_TAC [|- !x y. x+y = y+x]

   then applying this tactic to the term:

       ((a + b) + c) = (b + a)                    =
                                                /   \
         I.e.--->               subterm 1 -->  +     +  <-- subterm 2
                                              / \   / \
                              subterm 3 -->  +   c b   a
                                            / \
                                           a   b

    will result subterms 1 and 2, but NOT subterm 3, being rewritten.

    What Dave probably wanted was to rewrite the first subterm encountered
    in a left-to-right depth-first search of the term to be rewritten.
    This is a bit more difficult to do, since there is no simple built-in
    strategy for this.  Suppose, for example, we wanted to rewrite
    only subterm 1 in the term shown above.  One possibility is to create
    our own special-purpose rewriting strategy, as follows:

      letrec DEPTH_FIRST_CONV conv tm =
         FIRST_CONV
          [conv;                                % try it here               %
           RATOR_CONV (DEPTH_FIRST_CONV conv);  % or else try left subtree  %
           RAND_CONV  (DEPTH_FIRST_CONV conv);  % or else try right subtree %
           ABS_CONV   (DEPTH_FIRST_CONV conv)]  % or go through a lambda    %
         tm;;

    Given this trivial operation on conversions, the rewriting tactic
    we want is:

      let ONCE_LEFT_TO_RIGHT_DEPTH_FIRST_REWRITE_TAC =
          GEN_REWRITE_TAC DEPTH_FIRST_CONV basic_rewrites;;

    Now, if we apply this grotesquely-named tactic as follows:

      let sg,p =
          ONCE_LEFT_TO_RIGHT_DEPTH_FIRST_REWRITE_TAC [ADD_SYM]
             ([],"(a + b) + c = (b + a)");;

    we get:

     sg = [([], "c + (a + b) = b + a")] : goal list
     p = - : proof

    That is, only subterm 1 gets rewritten.


    A large variety of rewriting strategies can be programmed in the same
    simple way.  They're not built-in, but (as is shown by the example above)
    they are easy to program.


2: In the context of the original message, the question had to do with
   rewriting with specialized theorems.  All the built-in rewriting
   tools fully generalize the equations they are given before trying
   to rewrite with them (at least, this is one way to look at it). So,
   for example,

        ONCE_REWRITE_TAC [|- !x y. x+y = y+x]

   behaves exactly the same as:

        ONCE_REWRITE_TAC [SPECL ["a:num";"b:num"] |- !x y, x+y = y+x]

   provided "a:num" and "b:num" are variables.

   For the operation Dave wanted to carry out in his example, he should
   have used substitution, which doesn't do any matching and instantiation
   of the free variables.  For example:

       SUBST_TAC [|- a+b = b+a] ([], "a+b = 1+2")

   will result in the subgoal: "b+a = 1+2".  But doing:

       ONCE_REWRITE_TAC [|- a+b = b+a] ([], "a+b = 1+2")

   will result in the subgoal: "b+a = 2+1".


3: When there is only one assumption t on the assumption list,
   ASM_REWRITE_TAC [] can differ from REWRITE_TAC [|- t] if the
   term t has free variables.  Executing:

     ASM_REWRITE_TAC [] (["x+y = y+x"], "(x+y) = (1+2)")

   results in "(y+x) = (1+2)" because the variables "x" and "y" in
   the assumption CAN'T be instantiated to anything.  You can think
   of free variables in the assumption list as constants.  When executing:

     ONCE_REWRITE_TAC [|- x+y = y+x ] ([], "(x+y) = (1+2)")

   on the other hand, the variables "x" and "y" in the theorem
   are free, and can be instantiated to any two terms of type :num.
   So the result is:  "(y+x) = (2+1)"


I hope these remarks are helpful.

Tom

