I want to explain GEN_REWRITE_TAC, which I just understood (partly because of 
Rob and Michael's advice here about is_comb etc), and to argue that 
1) HOL programmers are very good at the pure math skill of adjoint functor, and
2) getting mathematicians to use HOL may require an interface that hides the 
adjoint functor, as mathematicians are not used to using adjoint functor in 
this way.
I suspect these points 1 & 2 hold for most proof assistants, e.g. Coq, which I 
was surprised to learn is based on LCF and ocaml/camlp, just like HOL Light.

Currying is the simplest example of using adjoint functors, which basically 
means the `exponential law', the bijection between sets of functions
C^(A x B) and (C^B)^A.  
Here's an example of the HOL adjoint functor skill that I had to work very hard 
to understand a while back.  Let's take as an example this 
Multivariate/topology.ml tactic 

FIRST_ASSUM(MP_TAC o SPEC `&1 / &2`)

To understand this, we need to think about the adjoint functors involved here: 
type goal = (string * thm) list * term;;
type goalstate = (term list * instantiation) * goal list * justification;;
type tactic = goal -> goalstate;;
type thm_tactic = thm -> tactic
FIRST_ASSUM : thm_tactic -> tactic
MP_TAC : thm_tactic
SPEC : term -> thm -> thm
(I this of a goalstate as a list of goals, although I guess that's just the 
middle coordinate.)

So SPEC `&1 / &2` has type thm -> thm, 
MP_TAC o SPEC `&1 / &2` has type thm -> tactic = thm_tactic, and 
FIRST_ASSUM(MP_TAC o SPEC `&1 / &2`) is the tactic obtained by applying this 
thm_tactic to the goal ([A1; ...; An], g) and producing the goalstate which 
replaces the last goal with 
([A1; ...; An], t ==> g), where t = SPEC `&1 / &2` An.  
Understanding that just takes good adjoint functor skills, and eventually I was 
able to work this exercise, but mathematicians don't expect to have to their 
adjoint functor skills here.  

John hid the adjoint functors involved in FIRST_ASSUM with "so" in the HOL 
Light tutorial section 12.1 "Towards more readable proofs", while Freek in 
miz3.ml used "-", as I did in my derivative readable.ml. 

GEN_REWRITE_TAC gives a great exercise in adjoint functor, and I'll use as an 
example my port of the page 90 tutorial theorem BINOMIAL_THEOREM in 
RichterHilbertAxiomGeometry/readable.ml.  A conversion (conv), has type 
term -> thm.  A conversional, like RAND_CONV, has type 
conv -> conv, and the ref manual says 
RAND_CONV c `t1 t2` applies c to the operand of the application `t1 t2` to 
produce an theorem equation
|- t1 t2 = t1 t2'.  Such equations are good for rewriting.  Now 
REWR_CONV : thm -> term -> thm
and for thm th which is an equation l = r, 
REWR_CONV th is the conversion which takes a term tm and tries to match it with 
l and return |- tm = tm', where tm' is a version of r.  Note that if we had a 
conversional cnvl, we can produce a new conversion 
cnvl (REWR_CONV th).  Now 
GEN_REWRITE_TAC : (conv -> conv) -> thm list -> tactic
and I believe that GEN_REWRITE_TAC cnvl [th1,...,thn]
applies the conversion cnvl (REWR_CONV thi) to the goal, for i = 1,...,n.  
I hope I got that right.  I can't understand the ref manual's description of 
GEN_REWRITE_TAC, but simp.ml defines
let GEN_REWRITE_TAC cnvl thl = CONV_TAC(GEN_REWRITE_CONV cnvl thl);;
and 
CONV_TAC : conv -> tactic, and CONV_TAC c is a tactic that applies c to the 
goal.  

Let's step through my proof of BINOMIAL_THEOREM:

needs "RichterHilbertAxiomGeometry/readable.ml";;
interactive_goal `;
  ∀n. (x + y) EXP n = nsum(0..n) (\k. binom(n,k) * x EXP k * y EXP (n - k))
`;;
interactive_proof `;
    ∀f n. nsum (0.. SUC n) f = f(0) + nsum (0..n) (λi. f (SUC i))     
[Nsum0SUC] by simplify LE_0 ADD1 NSUM_CLAUSES_LEFT NSUM_OFFSET;
    MATCH_MP_TAC num_INDUCTION;
    simplify EXP NSUM_SING_NUMSEG binom SUB_0 MULT_CLAUSES;
    intro_TAC ∀n, nThm;
    rewrite Nsum0SUC binom RIGHT_ADD_DISTRIB NSUM_ADD_NUMSEG GSYM NSUM_LMUL 
ADD_ASSOC;
    rewriteR ADD_SYM;
`;;

The last step used rewriteR = GEN_REWRITE_TAC (RAND_CONV)
which I'll pass over as being to easy and go on to the next step which uses a 
more complicated GEN_REWRITE_TAC.  To motivate the next step, look at the 
left-hand argument of binary operator + in the rand (i.e. RHS of the equation) 
of the goal:

(fst o (dest_binop `(+):num->num->num`) o rand)
`nsum (0..n) (\x'. x * binom (n,x') * x EXP x' * y EXP (n - x')) +
 nsum (0..n) (\x'. y * binom (n,x') * x EXP x' * y EXP (n - x')) =
 nsum (0..n) (\i. binom (n,i) * x EXP SUC i * y EXP (SUC n - SUC i)) +
 1 * x EXP 0 * y EXP (SUC n - 0) +
 nsum (0..n) (\i. binom (n,SUC i) * x EXP SUC i * y EXP (SUC n - SUC i))`;;

  `nsum (0..n) (\i. binom (n,i) * x EXP SUC i * y EXP (SUC n - SUC i))`

I want to rewrite this with SUB_SUC and EXP, and we can do that using 
rewriteRLDepth = GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o DEPTH_CONV) and 
LAND_CONV : conv -> conv 
which applies a conversion to left-hand argument of binary operator.  Evaluate

interactive_proof `;
    rewriteRLDepth SUB_SUC EXP;
`;;

and the goal is now 

`nsum (0..n) (\x'. x * binom (n,x') * x EXP x' * y EXP (n - x')) +
 nsum (0..n) (\x'. y * binom (n,x') * x EXP x' * y EXP (n - x')) =
 nsum (0..n) (\i. binom (n,i) * (x * x EXP i) * y EXP (n - i)) +
 1 * x EXP 0 * y EXP (SUC n - 0) +
 nsum (0..n) (\i. binom (n,SUC i) * x EXP SUC i * y EXP (SUC n - SUC i))`

I got my selective rewrite, and here's the rest of the proof:

interactive_proof `;
    rewrite MULT_AC EQ_ADD_LCANCEL MESON [binom] [1 = binom(n, 0)] GSYM 
Nsum0SUC;
    simplify NSUM_CLAUSES_RIGHT ARITH_RULE [0 < SUC n  ∧  0 <= SUC n] LT 
BINOM_LT MULT_CLAUSES ADD_CLAUSES SUC_SUB1;
    simplify ARITH_RULE [k <= n  ⇒  SUC n - k = SUC(n - k)] EXP MULT_AC;
`;;
let BINOMIAL_THEOREM = top_thm();;

 val BINOMIAL_THEOREM : thm =
  |- !n. (x + y) EXP n =
         nsum (0..n) (\k. binom (n,k) * x EXP k * y EXP (n - k))

I want to explain this GEN_REWRITE_TAC command, as it looks backwards to me.   
How did
fst o (dest_binop `(+):num->num->num`) o rand
turn into  
RAND_CONV o LAND_CONV o DEPTH_CONV ?  
The conversion 
(RAND_CONV o LAND_CONV o DEPTH_CONV) c 
applies the conversion 
(LAND_CONV o DEPTH_CONV) c to the rand above, and this applies the conversion 
DEPTH_CONV c
to the left-hand argument 
`(nsum (0..n) (\i. binom (n,i) * x EXP SUC i * y EXP (SUC n - SUC i)))`
of binary operator +.
I'm not real clear on DEPTH_CONV, which applies a conversion repeatedly to all 
the sub-terms of a term, in bottom-up order, but John used it the tutorial, and 
it works here.  

That was really hard work for me, and I think I'm a good mathematician.  The 
point is that we can read off what we wanted from the name rewriteRLDepth going 
left to right:
take the operand, and take the left-hand argument of binary operator + of that, 
and do a Depth rewriting on that.

For an exercise, let's redo the above GEN_REWRITE_TAC for practice, and get rid 
of the DEPTH_CONV.  First note that we can get the part we want to rewrite with 
SUB_SUC and EXP with 

(rand o rand o rand o snd o dest_abs o rand o fst o (dest_binop 
`(+):num->num->num`) o rand)
`nsum (0..n) (\x'. x * binom (n,x') * x EXP x' * y EXP (n - x')) +
 nsum (0..n) (\x'. y * binom (n,x') * x EXP x' * y EXP (n - x')) =
 nsum (0..n) (\i. binom (n,i) * x EXP SUC i * y EXP (SUC n - SUC i)) +
 1 * x EXP 0 * y EXP (SUC n - 0) +
 nsum (0..n) (\i. binom (n,SUC i) * x EXP SUC i * y EXP (SUC n - SUC i))`;;

 `SUC n - SUC i`

(fst o (dest_binop `(*):num->num->num`) o rand o snd o dest_abs o rand o fst o 
(dest_binop `(+):num->num->num`) o rand)
`nsum (0..n) (\x'. x * binom (n,x') * x EXP x' * y EXP (n - x')) +
 nsum (0..n) (\x'. y * binom (n,x') * x EXP x' * y EXP (n - x')) =
 nsum (0..n) (\i. binom (n,i) * x EXP SUC i * y EXP (SUC n - SUC i)) +
 1 * x EXP 0 * y EXP (SUC n - 0) +
 nsum (0..n) (\i. binom (n,SUC i) * x EXP SUC i * y EXP (SUC n - SUC i))`;;

`x EXP SUC i`

So we need two new GEN_REWRITE_TAC commands and tactics: 

let rewriteRLRARRR = GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV o 
ABS_CONV o RAND_CONV o RAND_CONV o RAND_CONV);;

let rewriteRLRARL = GEN_REWRITE_TAC (RAND_CONV o LAND_CONV o RAND_CONV o 
ABS_CONV o RAND_CONV o LAND_CONV);;

    rewriteRLRARRR SUB_SUC;
    rewriteRLRARL EXP;

Here's the finished proof:

let BINOMIAL_THEOREM = theorem `;
  ∀n. (x + y) EXP n = nsum(0..n) (\k. binom(n,k) * x EXP k * y EXP (n - k))

  proof
    ∀f n. nsum (0.. SUC n) f = f(0) + nsum (0..n) (λi. f (SUC i))     
[Nsum0SUC] by simplify LE_0 ADD1 NSUM_CLAUSES_LEFT NSUM_OFFSET;
    MATCH_MP_TAC num_INDUCTION;
    simplify EXP NSUM_SING_NUMSEG binom SUB_0 MULT_CLAUSES;
    intro_TAC ∀n, nThm;
    rewrite Nsum0SUC binom RIGHT_ADD_DISTRIB NSUM_ADD_NUMSEG GSYM NSUM_LMUL 
ADD_ASSOC;
    rewriteR ADD_SYM;
    rewriteRLRARRR SUB_SUC;
    rewriteRLRARL EXP;
    rewrite MULT_AC EQ_ADD_LCANCEL MESON [binom] [1 = binom(n, 0)] GSYM 
Nsum0SUC;
    simplify NSUM_CLAUSES_RIGHT ARITH_RULE [0 < SUC n  ∧  0 <= SUC n] LT 
BINOM_LT MULT_CLAUSES ADD_CLAUSES SUC_SUB1;
    simplify ARITH_RULE [k <= n  ⇒  SUC n - k = SUC(n - k)] EXP MULT_AC;
  qed;
`;;

val BINOMIAL_THEOREM : thm =
  |- !n. (x + y) EXP n =
         nsum (0..n) (\k. binom (n,k) * x EXP k * y EXP (n - k))

-- 
Best,
Bill

------------------------------------------------------------------------------
CenturyLink Cloud: The Leader in Enterprise Cloud Services.
Learn Why More Businesses Are Choosing CenturyLink Cloud For
Critical Workloads, Development Environments & Everything In Between.
Get a Quote or Start a Free Trial Today. 
http://pubads.g.doubleclick.net/gampad/clk?id=119420431&iu=/4140/ostg.clktrk
_______________________________________________
hol-info mailing list
hol-info@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/hol-info

Reply via email to