Thm.mk_axiom_thm accepts a caller-supplied Nonce.t, but the nonce is neither consumed nor permanently bound to the axiom proposition. The same nonce can therefore introduce multiple unrelated propositions.
I am unsure whether this is best classified as a soundness issue or as an API/design issue, but as it stands there isn't a clean story for axiom tracking that one might have hoped for from Tag.
To see what I mean, consider running:
open HolKernel;
val n = Nonce.mk "ETA_AX";
(* Register n for the genuine standard ETA axiom. *)
val eta =
Thm.mk_axiom_thm (n, Thm.concl boolTheory.ETA_AX);
val _ = Theory.register_replayed_axiom eta;
(* Reuse n for an unrelated proposition. *)
val bad = Thm.mk_axiom_thm (n, boolSyntax.F);
This would enable:
null (Thm.hyp bad); (* true *)
Term.aconv (Thm.concl bad) boolSyntax.F;
Tag.dest_tag (Thm.tag bad); (* ([], ["ETA_AX"]) *)
Theory.uptodate_thm bad; (* true *)
Theory.current_axioms() also does not show the replayed-axiom registry.
I'm guessing with a name like "nonce" the intention for this mechanism was more to be actually one-shot, e.g.:
Nonce.mk name creates a fresh nonce.
- The first
mk_axiom_thm (n, proposition) atomically binds n to that proposition.
- Any later call to
mk_axiom_thm with n fails.
register_replayed_axiom verifies that the theorem's conclusion matches the proposition already bound to its nonce.
- Propagating the nonce through theorem tags remains unrestricted.
(Obviously, consumption should be thread-safe and should not be undone by Context.restore.)
Alternatively, mk_axiom_thm could accept (name, proposition) and mint the nonce internally.
Thm.mk_axiom_thmaccepts a caller-suppliedNonce.t, but the nonce is neither consumed nor permanently bound to the axiom proposition. The same nonce can therefore introduce multiple unrelated propositions.I am unsure whether this is best classified as a soundness issue or as an API/design issue, but as it stands there isn't a clean story for axiom tracking that one might have hoped for from
Tag.To see what I mean, consider running:
This would enable:
Theory.current_axioms()also does not show the replayed-axiom registry.I'm guessing with a name like "nonce" the intention for this mechanism was more to be actually one-shot, e.g.:
Nonce.mk namecreates a fresh nonce.mk_axiom_thm (n, proposition)atomically bindsnto that proposition.mk_axiom_thmwithnfails.register_replayed_axiomverifies that the theorem's conclusion matches the proposition already bound to its nonce.(Obviously, consumption should be thread-safe and should not be undone by
Context.restore.)Alternatively,
mk_axiom_thmcould accept(name, proposition)and mint the nonce internally.