Zulip Chat Archive
Stream: new members
Topic: Given (A : Set α) and (a ∈ A) conclude that (a : α)
JoXn S Costello (Nov 07 2025 at 00:01):
I have a situation where I have (A : Set α) and (a ∈ A) by construction, so Lean concludes that (a : ↑A). I would like to coerce a to type α, but I can't find anything that would help me do that.
A is defined as
let A : Set α := { x : α | p x }
So clearly a ∈ A implies a : α, it's right there in the definition. But I can't find any way to extract that information. Any help would be appreciated here.
Weiyi Wang (Nov 07 2025 at 00:04):
Could you provide #mwe? What you described doesn't immediately makes sense. To be able to write a ∈ A legally, you will need to have (a : α) in the first place. That's not something that can be or needs to be extracted because it should be there already
Weiyi Wang (Nov 07 2025 at 00:05):
(in other words, x : y is not a proposition in Lean / type theory)
Matt Diamond (Nov 07 2025 at 00:07):
No, it makes sense... they have a value whose type is the coerced set. I think @JoXn S Costello just needs an explanation of exactly what happens when Lean coerces a Set to a type. Once they understand that, the solution should (hopefully) be obvious.
Though I do think more context (or even better, a #mwe) couldn't hurt.
Aaron Liu (Nov 07 2025 at 00:08):
might you be looking for (a : A)?
Matt Diamond (Nov 07 2025 at 00:09):
@Aaron Liu what I think he's looking for is a.val
Matt Diamond (Nov 07 2025 at 00:09):
when Lean coerces a Set to a type, it creates a docs#Subtype via docs#Set.Elem
Matt Diamond (Nov 07 2025 at 00:11):
@JoXn S Costello so if you have (a : ↑A) and you want a value of type α, you can just use a.val to extract the value from the Subtype, as a is just a combination of a value and a proof that the value is a member of the set
Aaron Liu (Nov 07 2025 at 00:12):
Aaron Liu said:
might you be looking for
(a : A)?
typo, meant to write (a : α)
Matt Diamond (Nov 07 2025 at 00:12):
yeah you could just coerce it too
Matt Diamond (Nov 07 2025 at 00:15):
also this might be an #xy problem which is why a #mwe would be nice
JoXn S Costello (Nov 07 2025 at 01:58):
I'm trying, for fun and to learn something, to formalize Diaconescu's theorem, so I start out with
let A : Set Bool := { x : Bool | (x = true) ∨ p }
let B : Set Bool := { x : Bool | (x = false) ∨ p}
Classical.choice will "construct" me an a ∈ A, but I couldn't do anything useful like compare it to true in a match etc. a.val is exactly what I needed to lift a back up to Bool. Thank you!
(To make Classical.choice run at all you need to provide a proof of Nonempty A, but once you have done that choice quite reasonably produces values of type ↑A. Even figuring out how to construct Nonempty A has been instructive.)
I don't think there is any way I would have figured out that the Subtype info was what I needed, since I'm mostly relying on tutorial-level documents like "Theorem Proving in Lean 4" which don't even mention that this could be an issue. Don't get me wrong, that's a fantastic resource. But it's also got a whole section on "Propositions as Types" that doesn't dig into the differences between propositions and types, and it has a section on typeclass coercion that gives lots of advanced tips but it doesn't seem to mention subtypes...
JoXn S Costello (Nov 07 2025 at 02:12):
I should mention that I know that Lean uses Diaconescu's theorem to prove Classical.em but I am not going to let that spoil my fun!
Aaron Liu (Nov 07 2025 at 02:13):
By the way, you can match on a too
JoXn S Costello (Nov 07 2025 at 02:18):
When I type
match choice_A with
| true =>
Lean helpfully tells me Type mismatch ⏎true⏎ has type⏎Bool⏎but is expected to have type ⏎↑A⏎, and that's what started the adventure that led me here.
Aaron Liu (Nov 07 2025 at 02:18):
match choice_A with
| Subtype.mk true hA =>
Aaron Liu (Nov 07 2025 at 02:19):
or more commonly,
match choice_A with
| ⟨true, hA⟩ =>
suhr (Nov 07 2025 at 11:32):
open Classical in
def eq_choose {U V: α → Prop}(uv: U = V)
: (eu: ∃x, U x) → (ev: ∃x, V x) → choose eu = choose ev :=
uv ▸ (λ_ _ ↦ rfl)
open Classical in
example (P: Prop) : P ∨ ¬P :=
let U := λx ↦ (x = true) ∨ P
let V := λx ↦ (x = false) ∨ P
let eu: ∃x, U x := ⟨true, Or.inl rfl⟩
let ev: ∃x, V x := ⟨false, Or.inl rfl⟩
let u := choose eu; let v := choose ev
let p_uv: P → u = v :=
λp ↦
let uv: U = V :=
funext $ λ_ ↦ propext ⟨λ_ ↦ Or.inr p, λ_ ↦ Or.inr p⟩
eq_choose uv eu ev
match (choose_spec eu), (choose_spec ev) with
| Or.inr p, _ => Or.inl p
| _, Or.inr p => Or.inl p
| Or.inl (ut: u = true),
Or.inl (vf: v = false) => Or.inr $ (ut ▸ vf ▸ Bool.noConfusion) ∘ p_uv
suhr (Nov 07 2025 at 11:34):
I just happen to have a readable proof of Diaconescu's theorem in Lean.
Eric Rodriguez (Nov 07 2025 at 14:18):
there's a proof in core lean (docs#Classical.em) but I think JoXn is trying to prove it themselves
Last updated: Dec 20 2025 at 21:32 UTC