Zulip Chat Archive
Stream: lean4
Topic: forbid_axioms
Johan Commelin (May 15 2023 at 10:28):
Is it possible to have a Lean 4 command
#forbid_axioms My.Fancy.Constant My.Other.Axiom
at the top of some file, which makes sure that all the decls in that file can not depend on those axioms? (If they try to depend on the axioms, this should result in an error.)
It might be easier to have some linter at the bottom of the file, with errors reported at the line that invokes the linter. That would be a good start. But it would be really nice if errors are reported while writing the decl, at the line where a "forbidden" lemma is used.
Ruben Van de Velde (May 15 2023 at 10:32):
If it goes at the start, it might be good to make it section-scoped rather than file-scoped
Mario Carneiro (May 15 2023 at 10:34):
You might be able to hack that together with a "linter" that makes errors instead of warnings
Mario Carneiro (May 15 2023 at 10:35):
since linters get to spy on every command as they go by
Mario Carneiro (May 15 2023 at 10:35):
it won't catch decls created directly via addDecl
though
Mario Carneiro (May 15 2023 at 10:36):
plus you have to reconstruct the declaration to check from the syntax, since you are just given the raw command syntax
Eric Wieser (May 15 2023 at 12:23):
#10954 seems relevant here
Gabriel Ebner (May 15 2023 at 16:42):
Mario Carneiro said:
it won't catch decls created directly via
addDecl
though
You can always do what whatsnew
does and just compare the two environments. (Beware of the quadratic runtime though.)
Johan Commelin (May 16 2023 at 06:18):
How do I programmatically ask for the axioms of a certain decl?
Johan Commelin (May 16 2023 at 06:19):
Oooh cool! You can go-to-defn on #print axioms
:bulb:
Johan Commelin (May 16 2023 at 07:00):
Here is my current broken attempt:
import Lean.Elab.Print
import Std.Tactic.Lint
import Mathlib.Tactic.RunCmd
namespace Lean
namespace Parser.Command
@[builtin_command_parser] def forbiddenAxioms := leading_parser
"#forbiddenAxioms " >> ident
end Parser.Command
namespace Elab.Command
private def forbiddenAxioms (bad : List Name) : CommandElabM Unit := do
let env ← getEnv
let decls ← liftCoreM Std.Tactic.Lint.getDeclsInCurrModule
decls.forM fun n ↦
let axs := ((((CollectAxioms.collect n).run env).run {}).2).axioms.toList
let l := bad.filter fun a ↦ a ∈ axs
if l.isEmpty then pure ()
else logInfo m!"'{n}' depends on: {l}"
@[builtin_command_elab Parser.Command.forbiddenAxioms]
def elabForbiddenAxioms : CommandElab
| `(#forbiddenAxioms%$tk $id) => withRef tk do -- <== ERROR: expected token
let cs ← resolveGlobalConstWithInfos id
cs.forM printAxiomsOf
| _ => throwUnsupportedSyntax
end Elab.Command
end Lean
axiom LEM (P : Prop) : P ∨ ¬P
theorem test1 (P : Prop) : ¬P ∨ P :=
(LEM P).elim .inr .inl
def test2 (P : Prop) : True := trivial
open Lean Elab Command in
run_cmd
forbiddenAxioms [`LEM] -- prints: 'LEM' depends on [LEM], 'test1' depends on [LEM]
Johan Commelin (May 16 2023 at 07:01):
There is red squiggles under #forbiddenAxioms
at the indicated line
Mario Carneiro (May 16 2023 at 07:06):
@[builtin_*]
attributes should not be used outside lean core
Mario Carneiro (May 16 2023 at 07:06):
you should just use syntax
Johan Commelin (May 16 2023 at 07:07):
could you please tell me how to do just that?
Mario Carneiro (May 16 2023 at 07:10):
namespace Lean
open Elab Command
private def forbiddenAxioms (bad : List Name) : CommandElabM Unit := do
let env ← getEnv
let decls ← liftCoreM Std.Tactic.Lint.getDeclsInCurrModule
decls.forM fun n ↦
let axs := ((((CollectAxioms.collect n).run env).run {}).2).axioms.toList
let l := bad.filter fun a ↦ a ∈ axs
if l.isEmpty then pure ()
else logInfo m!"'{n}' depends on: {l}"
open private printAxiomsOf from Lean.Elab.Print
elab tk:"#forbiddenAxioms " id:ident : command => do
let cs ← resolveGlobalConstWithInfos id
withRef tk <| cs.forM printAxiomsOf
end Lean
Johan Commelin (May 16 2023 at 07:11):
Ok, thanks, I'll try to take it from there
Johan Commelin (May 16 2023 at 07:38):
Result so far
import Lean.Elab.Print
import Std.Tactic.Lint
namespace Lean
def Parser.Command.forbiddenAxioms := leading_parser
"#forbiddenAxioms " >> termParser
open Elab Command
private def forbiddenAxioms (bad : List Name) : CommandElabM Unit := do
let env ← getEnv
let decls ← liftCoreM Std.Tactic.Lint.getDeclsInCurrModule
decls.forM fun n ↦
let axs := ((((CollectAxioms.collect n).run env).run {}).2).axioms.toList
let l := bad.filter fun a ↦ a ∈ axs
if l.isEmpty then pure ()
else logInfo m!"'{n}' depends on: {l}"
open private printAxiomsOf from Lean.Elab.Print
elab tk:"#forbiddenAxioms " ids:ident* : command => withRef tk do
let ns ← ids.mapM resolveGlobalConstNoOverloadWithInfo
withRef tk <| forbiddenAxioms ns.toList
end Lean
Mario Carneiro (May 16 2023 at 09:56):
you don't want the first def
there, the elab
already does everything
Johan Commelin (May 16 2023 at 10:28):
good point, thanks!
Last updated: Dec 20 2023 at 11:08 UTC