Coq like Tactics
Revision: r154 で新規実装された4つのTactic
HYP DESTRUCT_TAC FIX_TAC INTRO_TAC
は(鶏風ではありますが)ラベリングには便利です.
例えば,GEN_TACやDISCH_TAC,DISJ*_TACの働きを有するのが
INTRO_TAC
http://www.cl.cam.ac.uk/~jrh13/hol-light/HTML/INTRO_TAC.html
です.
# g `!x y. (A0 /\ A1) \/ A2 \/ (A3 /\ A4 /\ A5) ==> A6 \/ (A7 /\ A8) ==> !w. C1 \/ C2 \/ C3`;; Warning: inventing type variables Warning: Free variables in goal: A0, A1, A2, A3, A4, A5, A6, A7, A8, C1, C2, C3 val it : goalstack = 1 subgoal (1 total) `!x y. A0 /\ A1 \/ A2 \/ A3 /\ A4 /\ A5 ==> A6 \/ A7 /\ A8 ==> (!w. C1 \/ C2 \/ C3)` # e( INTRO_TAC "! x y ; 0 1 | 2 | 3 4 5" );; val it : goalstack = 3 subgoals (3 total) 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) `A6 \/ A7 /\ A8 ==> (!w. C1 \/ C2 \/ C3)` 0 [`A2`] (2) `A6 \/ A7 /\ A8 ==> (!w. C1 \/ C2 \/ C3)` 0 [`A0`] (0) 1 [`A1`] (1) `A6 \/ A7 /\ A8 ==> (!w. C1 \/ C2 \/ C3)` # r 2;; val it : goalstack = 1 subgoal (3 total) 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) `A6 \/ A7 /\ A8 ==> (!w. C1 \/ C2 \/ C3)` # e( INTRO_TAC "6 | 7 8" );; val it : goalstack = 2 subgoals (4 total) 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) 3 [`A7`] (7) 4 [`A8`] (8) `!w. C1 \/ C2 \/ C3` 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) 3 [`A6`] (6) `!w. C1 \/ C2 \/ C3` # e( INTRO_TAC "! w" );; val it : goalstack = 1 subgoal (4 total) 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) 3 [`A6`] (6) `C1 \/ C2 \/ C3` # e( INTRO_TAC "# 3" );; val it : goalstack = 1 subgoal (4 total) 0 [`A3`] (3) 1 [`A4`] (4) 2 [`A5`] (5) 3 [`A6`] (6) `C3`
同様に,既存のthmに対するLABEL_TAC,CHOOSE_TACの働きを持つのが
DESTRUCT_TAC
http://www.cl.cam.ac.uk/~jrh13/hol-light/HTML/DESTRUCT_TAC.html
です.
# g `C:bool`;; Warning: Free variables in goal: C val it : goalstack = 1 subgoal (1 total) `C` # e( DESTRUCT_TAC "z | p" (ARITH_RULE`n=0 \/ 0<n`) );; val it : goalstack = 2 subgoals (2 total) 0 [`0 < n`] (p) `C` 0 [`n = 0`] (z) `C` # r 1;; val it : goalstack = 1 subgoal (2 total) 0 [`0 < n`] (p) `C` # SPEC`n:num`num_CASES;; val it : thm = |- n = 0 \/ (?n'. n = SUC n') # e( DESTRUCT_TAC "q | @ n' . r" (SPEC`n:num`num_CASES) );; val it : goalstack = 2 subgoals (3 total) 0 [`0 < n`] (p) 1 [`n = SUC n'`] (r) `C` 0 [`0 < n`] (p) 1 [`n = 0`] (q) `C`
また,DISCH_THEN で前件を定理として DESTRUCT_TAC "ラベル" に渡せば
# g `A==>(?x.x=0)==>x=0`;; Warning: Free variables in goal: A, x val it : goalstack = 1 subgoal (1 total) `A ==> (?x. x = 0) ==> x = 0` # e( DISCH_THEN (DESTRUCT_TAC "0") );; val it : goalstack = 1 subgoal (1 total) 0 [`A`] (0) `(?x. x = 0) ==> x = 0` # e( DISCH_THEN (DESTRUCT_TAC "@ x . 1") );; Exception: Failure "X_CHOOSE_TAC". # e( DISCH_THEN (DESTRUCT_TAC "@ x' . 1") );; val it : goalstack = 1 subgoal (1 total) 0 [`A`] (0) 1 [`x' = 0`] (1) `x = 0`
のようにも使えます.
さらに,INTRO_TAC を用いると,既存の仮定にラベルを付ける NAME_TAC も簡単に作れます.
# let NAME_TAC (s:string) = REPEAT ((POP_ASSUM MP_TAC) THEN (REWRITE_TAC [IMP_IM P]) ) THEN INTRO_TAC s ;; val ( NAME_TAC ) : string -> tactic = <fun> # g `x=1 /\ y=1 /\ z=1 ==> a=1` ;; Warning: Free variables in goal: a, x, y, z val it : goalstack = 1 subgoal (1 total) `x = 1 /\ y = 1 /\ z = 1 ==> a = 1` # e( REPEAT STRIP_TAC );; val it : goalstack = 1 subgoal (1 total) 0 [`x = 1`] 1 [`y = 1`] 2 [`z = 1`] `a = 1` # e( NAME_TAC "0 1 2" );; val it : goalstack = 1 subgoal (1 total) 0 [`x = 1`] (0) 1 [`y = 1`] (1) 2 [`z = 1`] (2) `a = 1` # g `x=1 /\ y=1 \/ z=1 ==> a=1` ;; Warning: Free variables in goal: a, x, y, z val it : goalstack = 1 subgoal (1 total) `x = 1 /\ y = 1 \/ z = 1 ==> a = 1` # e( REPEAT STRIP_TAC );; val it : goalstack = 2 subgoals (2 total) 0 [`z = 1`] `a = 1` 0 [`x = 1`] 1 [`y = 1`] `a = 1` # e( NAME_TAC "0 1" );; val it : goalstack = 1 subgoal (2 total) 0 [`x = 1`] (0) 1 [`y = 1`] (1) `a = 1` # r 1;; val it : goalstack = 1 subgoal (2 total) 0 [`z = 1`] `a = 1` # e( NAME_TAC "0" );; val it : goalstack = 1 subgoal (2 total) 0 [`z = 1`] (0) `a = 1`