Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add (un)set_then_multiple_subgoals to control the behavior of THEN #113

Merged
merged 1 commit into from
Oct 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion Help/THEN.hlp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@ The application of {THEN} to a pair of tactics never fails.
The resulting tactic fails if {t1} fails when applied to the goal, or if
{t2} does when applied to any of the resulting subgoals.

If {unset_then_multiple_subgoals} is used, {THEN} is configured to fail
when {t1} generates more than one subgoal.
This is useful when one wants to check whether a proof written using {THEN} can
be syntactically converted to the `e` form.

\EXAMPLE
Suppose we want to prove the inbuilt theorem {DELETE_INSERT} ourselves:
{
Expand Down Expand Up @@ -61,6 +66,6 @@ If using this several times in succession, remember that {THEN} is
left-associative.

\SEEALSO
EVERY, ORELSE, THENL.
EVERY, ORELSE, THENL, unset_then_multiple_subgoals

\ENDDOC
34 changes: 34 additions & 0 deletions Help/unset_jrh_lexer.hlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
\DOC unset_jrh_lexer

\TYPE {unset_jrh_lexer : (preprocessor keyword)}

\SYNOPSIS
Updates the HOL Light preprocessor to respect OCaml's identifier convention.

\DESCRIBE
If a preprocessor reads {unset_jrh_lexer}, it switches its lexer to
use OCaml's identifier convention. This makes an identifier starting with a
capiter letter unusable as the name of a let binding, but enables using it as a
module constructor.
Modulo this side effect, {unset_jrh_lexer} is simply identical to {false}.
The lexer can be enabled again using {set_jrh_lexer}, which is identical to
{true} after preprocessing.

\EXAMPLE
{
# module OrdInt = struct type t = int let compare = (-) end;;
Toplevel input:
# module OrdInt = struct type t = int let compare = (-) end;;
^^^^^^
Parse error: 'type' or [ext_attributes] expected after 'module' (in
[str_item])
# unset_jrh_lexer;;
val it : bool = false
# module OrdInt = struct type t = int let compare = (-) end;;
module OrdInt : sig type t = int val compare : int -> int -> int end
}

\FAILURE
Never fails.

\ENDDOC
48 changes: 48 additions & 0 deletions Help/unset_then_multiple_subgoals.hlp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
\DOC unset_then_multiple_subgoals

\TYPE {unset_then_multiple_subgoals : (preprocessor keyword)}

\SYNOPSIS
Updates the HOL Light preprocessor to read {THEN} as an alternative operator
which fails if the first tactic creates more than one subgoal.

\KEYWORDS
tactical.

\DESCRIBE
If a preprocessor reads {unset_then_multiple_subgoals}, it starts to translate
{t1 THEN t2} into {then1_ t1 t2} which fails when {t1} generates more than one
subgoal.
This is useful when one wants to check whether a proof written using {THEN} can
be syntactically converted to the `e`-`g` form.
If this setting is on, {t1 THEN t2 THEN ..} and {e(t1);; e(t2);; ...}
have the same meaning (modulo the validity check).
After preprocessing, {unset_then_multiple_subgoals} is identical to the {false}
constant in OCaml.
To roll back the behavior of {THEN}, use {set_then_multiple_subgoals},
which is identical to {true} modulo its side effect.

This command is only available for OCaml 4.xx and above.

\EXAMPLE
{
# prove(`x + 1 = 1 + x /\ x + 2 = 2 + x`, CONJ_TAC THEN ARITH_TAC);;
val it : thm = |- x + 1 = 1 + x /\ x + 2 = 2 + x

# unset_then_multiple_subgoals;;
val it : bool = false
# prove(`x + 1 = 1 + x /\ x + 2 = 2 + x`, CONJ_TAC THEN ARITH_TAC);;
Exception: Failure "seqapply: Length mismatch".
# prove(`x + 1 = 1 + x /\ x + 2 = 2 + x`, CONJ_TAC THENL [ARITH_TAC; ARITH_TAC]);;
val it : thm = |- x + 1 = 1 + x /\ x + 2 = 2 + x
# prove(`x + 1 = 1 + x /\ x + 2 = 2 + x`, CONJ_TAC THENL (replicate ARITH_TAC 2));;
val it : thm = |- x + 1 = 1 + x /\ x + 2 = 2 + x
}

\FAILURE
Never fails.

\SEEALSO
e, THEN, VALID.

\ENDDOC
12 changes: 10 additions & 2 deletions pa_j/pa_j_4.xx_8.00.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,18 @@ value is_uppercase s = String.uppercase_ascii s = s;
value is_only_lowercase s = String.lowercase_ascii s = s && not(is_uppercase s);

value jrh_lexer = ref True;
value then_multiple_subgoals = ref True;

value jrh_identifier find_kwd id =
let jflag = jrh_lexer.val in
if id = "set_jrh_lexer" then
(let _ = jrh_lexer.val := True in ("",find_kwd "true"))
else if id = "unset_jrh_lexer" then
(let _ = jrh_lexer.val := False in ("",find_kwd "false"))
else if id = "set_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := True in ("",find_kwd "true"))
else if id = "unset_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := False in ("",find_kwd "false"))
else
try ("", find_kwd id) with
[ Not_found ->
Expand Down Expand Up @@ -1229,7 +1234,7 @@ value is_operator = do {
value translate_operator =
fun s ->
match s with
[ "THEN" -> "then_"
[ "THEN" -> if then_multiple_subgoals.val then "then_" else "then1_"
| "THENC" -> "thenc_"
| "THENL" -> "thenl_"
| "ORELSE" -> "orelse_"
Expand Down Expand Up @@ -3559,7 +3564,10 @@ EXTEND
| f = expr; "upto"; g = expr -> <:expr< ((upto $f$) $g$) >>
| f = expr; "F_F"; g = expr -> <:expr< ((f_f_ $f$) $g$) >>
| f = expr; "THENC"; g = expr -> <:expr< ((thenc_ $f$) $g$) >>
| f = expr; "THEN"; g = expr -> <:expr< ((then_ $f$) $g$) >>
| f = expr; "THEN"; g = expr ->
if then_multiple_subgoals.val
then <:expr< ((then_ $f$) $g$) >>
else <:expr< ((then1_ $f$) $g$) >>
| f = expr; "THENL"; g = expr -> <:expr< ((thenl_ $f$) $g$) >>
| f = expr; "ORELSE"; g = expr -> <:expr< ((orelse_ $f$) $g$) >>
| f = expr; "ORELSEC"; g = expr -> <:expr< ((orelsec_ $f$) $g$) >>
Expand Down
12 changes: 10 additions & 2 deletions pa_j/pa_j_4.xx_8.02.ml
Original file line number Diff line number Diff line change
Expand Up @@ -78,13 +78,18 @@ value is_uppercase s = String.uppercase_ascii s = s;
value is_only_lowercase s = String.lowercase_ascii s = s && not(is_uppercase s);

value jrh_lexer = ref True;
value then_multiple_subgoals = ref True;

value jrh_identifier find_kwd id =
let jflag = jrh_lexer.val in
if id = "set_jrh_lexer" then
(let _ = jrh_lexer.val := True in ("",find_kwd "true"))
else if id = "unset_jrh_lexer" then
(let _ = jrh_lexer.val := False in ("",find_kwd "false"))
else if id = "set_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := True in ("",find_kwd "true"))
else if id = "unset_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := False in ("",find_kwd "false"))
else
try ("", find_kwd id) with
[ Not_found ->
Expand Down Expand Up @@ -1229,7 +1234,7 @@ value is_operator = do {
value translate_operator =
fun s ->
match s with
[ "THEN" -> "then_"
[ "THEN" -> if then_multiple_subgoals.val then "then_" else "then1_"
| "THENC" -> "thenc_"
| "THENL" -> "thenl_"
| "ORELSE" -> "orelse_"
Expand Down Expand Up @@ -3559,7 +3564,10 @@ EXTEND
| f = expr; "upto"; g = expr -> <:expr< ((upto $f$) $g$) >>
| f = expr; "F_F"; g = expr -> <:expr< ((f_f_ $f$) $g$) >>
| f = expr; "THENC"; g = expr -> <:expr< ((thenc_ $f$) $g$) >>
| f = expr; "THEN"; g = expr -> <:expr< ((then_ $f$) $g$) >>
| f = expr; "THEN"; g = expr ->
if then_multiple_subgoals.val
then <:expr< ((then_ $f$) $g$) >>
else <:expr< ((then1_ $f$) $g$) >>
| f = expr; "THENL"; g = expr -> <:expr< ((thenl_ $f$) $g$) >>
| f = expr; "ORELSE"; g = expr -> <:expr< ((orelse_ $f$) $g$) >>
| f = expr; "ORELSEC"; g = expr -> <:expr< ((orelsec_ $f$) $g$) >>
Expand Down
12 changes: 10 additions & 2 deletions pa_j/pa_j_4.xx_8.03.ml
Original file line number Diff line number Diff line change
Expand Up @@ -88,13 +88,18 @@ value is_uppercase s = String.uppercase_ascii s = s;
value is_only_lowercase s = String.lowercase_ascii s = s && not(is_uppercase s);

value jrh_lexer = ref True;
value then_multiple_subgoals = ref True;

value jrh_identifier find_kwd id =
let jflag = jrh_lexer.val in
if id = "set_jrh_lexer" then
(let _ = jrh_lexer.val := True in ("",find_kwd "true"))
else if id = "unset_jrh_lexer" then
(let _ = jrh_lexer.val := False in ("",find_kwd "false"))
else if id = "set_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := True in ("",find_kwd "true"))
else if id = "unset_then_multiple_subgoals" then
(let _ = then_multiple_subgoals.val := False in ("",find_kwd "false"))
else
try ("", find_kwd id) with
[ Not_found ->
Expand Down Expand Up @@ -1298,7 +1303,7 @@ value is_operator = do {
value translate_operator =
fun s ->
match s with
[ "THEN" -> "then_"
[ "THEN" -> if then_multiple_subgoals.val then "then_" else "then1_"
| "THENC" -> "thenc_"
| "THENL" -> "thenl_"
| "ORELSE" -> "orelse_"
Expand Down Expand Up @@ -3734,7 +3739,10 @@ EXTEND
| f = expr; "upto"; g = expr -> <:expr< ((upto $f$) $g$) >>
| f = expr; "F_F"; g = expr -> <:expr< ((f_f_ $f$) $g$) >>
| f = expr; "THENC"; g = expr -> <:expr< ((thenc_ $f$) $g$) >>
| f = expr; "THEN"; g = expr -> <:expr< ((then_ $f$) $g$) >>
| f = expr; "THEN"; g = expr ->
if then_multiple_subgoals.val
then <:expr< ((then_ $f$) $g$) >>
else <:expr< ((then1_ $f$) $g$) >>
| f = expr; "THENL"; g = expr -> <:expr< ((thenl_ $f$) $g$) >>
| f = expr; "ORELSE"; g = expr -> <:expr< ((orelse_ $f$) $g$) >>
| f = expr; "ORELSEC"; g = expr -> <:expr< ((orelsec_ $f$) $g$) >>
Expand Down
4 changes: 2 additions & 2 deletions tactics.ml
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ let (VALID:tactic->tactic) =
(* Various simple combinators for tactics, identity tactic etc. *)
(* ------------------------------------------------------------------------- *)

let (THEN),(THENL) =
let (THEN),(THENL),then1_ =
let propagate_empty i [] = []
and propagate_thm th i [] = INSTANTIATE_ALL i th in
let compose_justs n just1 just2 insts2 i ths =
Expand Down Expand Up @@ -161,7 +161,7 @@ let (THEN),(THENL) =
let _,gls,_ as gstate = tac1 g in
if gls = [] then tacsequence gstate []
else tacsequence gstate tac2l in
then_,thenl_;;
then_,thenl_,(fun tac1 tac2 -> thenl_ tac1 [tac2]);;

let ((ORELSE): tactic -> tactic -> tactic) =
fun tac1 tac2 g ->
Expand Down
Loading