Zulip Chat Archive
Stream: metaprogramming / tactics
Topic: Issue writing a tactic
Brendan Seamas Murphy (Nov 04 2023 at 16:28):
I noticed that the inhabit
tactic uses Classical.choice
even if the goal is a Prop
(I would think we can just use Nonempty.elim
?). This seemed weird to me since the tactic already attempts to avoid classical reasoning if the target is a Prop
. I noticed this because unique_iff_subsingleton_and_nonempty
relies on Classical.choice
, which doesn't seem necessary (I was checking this because I wanted to understand the principle of unique choice better). I tried to modify the tactic to avoid choice
if the goal is a Prop
, but I'm not very familiar with metaprogramming (especially in Lean 4) and now I'm getting the error "(kernel) declaration has metavariables 'unique_iff_subsingleton_and_nonempty'" when I try and define
theorem unique_iff_subsingleton_and_nonempty (α : Sort u) :
Nonempty (Unique α) ↔ Subsingleton α ∧ Nonempty α :=
⟨fun ⟨u⟩ ↦ by constructor <;> exact inferInstance,
fun ⟨hs, hn⟩ ↦ by inhabit α; constructor; exact Unique.mk' α⟩
My modified version of the inhabit tactic is
theorem nonempty_elim_to_inhabited
(α : Sort*) (α_nonempty : Nonempty α) {p : Prop} (f : Inhabited α → p) : p :=
α_nonempty.elim <| f ∘ Inhabited.mk
def evalInhabit (goal : MVarId) (h_name : Option Ident) (term : Syntax) : TacticM MVarId := do
goal.withContext do
let e ← Tactic.elabTerm term none
let e_lvl ← Meta.getLevel e
let inhabited_e := mkApp (mkConst ``Inhabited [e_lvl]) e
let nonempty_e := mkApp (mkConst ``Nonempty [e_lvl]) e
let nonempty_e_pf ← synthInstance nonempty_e
let h_name : Name :=
match h_name with
| some h_name => h_name.getId
| none => `inhabited_h
-- start of new code
let e_isprop ← isProp e
let g_type ← getMainTarget
let g_isprop ← isProp g_type
let inhab_imp_g_type := Expr.forallE `a inhabited_e g_type .default
if g_isprop
then do
let n := `temp
let pf ← mkFreshExprMVar inhab_imp_g_type MetavarKind.syntheticOpaque n
let pf' ← Meta.mkAppM ``nonempty_elim_to_inhabited #[e, nonempty_e_pf, pf]
let (_, r) ← (← goal.assert h_name inhabited_e pf').intro1P
return r
else
-- end of new code
let pf ←
if e_isprop
then Meta.mkAppM ``nonempty_prop_to_inhabited #[e, nonempty_e_pf]
else Meta.mkAppM ``nonempty_to_inhabited #[e, nonempty_e_pf]
let (_, r) ← (← goal.assert h_name inhabited_e pf).intro1P
return r
Kevin Buzzard (Nov 04 2023 at 16:30):
Having looked at docs#unique_iff_subsingleton_and_nonempty I see that the unique part doesn't live in Type so my claim is incorrect!unique_iff_subsingleton_and_nonempty
needs choice because subsingleton
and nonempty
live in the Prop universe, and unique
lives in the Type universe, and the axiom of choice is precisely Lean's route from the Prop universe to the Type universe.
Timo Carlin-Burns (Nov 04 2023 at 16:32):
But the left hand side of unique_iff_subsingleton_and_nonempty
is Nonempty (Unique α)
which does live in Prop
Brendan Seamas Murphy (Nov 04 2023 at 16:35):
For reference, here's a modified version of unique_iff_subsingleton_and_nonempty
that doesn't depend on choice or the inhabit tactic
theorem unique_iff_subsingleton_and_nonempty (α : Sort u) :
Nonempty (Unique α) ↔ Subsingleton α ∧ Nonempty α :=
⟨fun ⟨u⟩ ↦ by constructor <;> exact inferInstance,
fun ⟨hs, hn⟩ ↦ by induction hn; constructor; apply uniqueOfSubsingleton; assumption⟩
Kevin Buzzard (Nov 04 2023 at 16:37):
yeah I've just proved it too. But why do you care about any of this? Mathlib is a classical library. I'm sure there are many uses of classical axioms which are unnecessary.
Brendan Seamas Murphy (Nov 04 2023 at 16:38):
Why does the inhabit tactic avoid using classical.choice at all?
Kevin Buzzard (Nov 04 2023 at 16:41):
I guess that's a question for whoever wrote that specific tactic?
Brendan Seamas Murphy (Nov 04 2023 at 16:41):
To answer your question directly, I wanted to work out some stuff about anafunctors without rebuilding a ton of basic definitions of category theory. Afaict apart from the choices of limits/colimits or choosing an inverse to an equivalence, most of the category theory implemented in mathlib already doesn't rely on classical reasoning. Reimplementing all that would be a pain and I would prefer to work with an existing codebase
Last updated: Dec 20 2023 at 11:08 UTC