Zulip Chat Archive
Stream: general
Topic: The "attach" trick for quotients?
mniip (Jan 27 2025 at 09:20):
Analogously to, say, List.attach
, it's possible to define Quotient.attach
with the following type:
def Quotient.attach {r : Setoid α} (q : Quotient r) : Trunc { x // ⟦x⟧ = q }
:= sorry
Normally when eliminating a quotient we have to show that the continuation is "proper" on its entire domain (Quotient.lift
), but with the "attach" trick we can weaken this assumption to only things that are equivalent to the actual value we're eliminating:
def Quotient.lift_attached {r : Setoid α} (q : Quotient r)
(f : α → β) (proper : ∀ x y, ⟦x⟧ = q → ⟦y⟧ = q → f x = f y)
: β
:= q.attach.lift (λt => f t.1) $ by
intro ⟨_, _⟩ ⟨_, _⟩
dsimp only
apply proper <;> assumption
We can get even lazier and only relate it to q.out
:
def Quotient.lift_attached' {r : Setoid α} (q : Quotient r)
(f : α → β) (proper : ∀ x, r x q.out → f x = f q.out)
: β
:= q.attach.lift (λt => f t.1) $ by
intro ⟨x, _⟩ ⟨y, _⟩
dsimp only
rw [proper x, proper y]
. exact Quotient.mk_eq_iff_out.mp ‹_›
. exact Quotient.mk_eq_iff_out.mp ‹_›
Here's a possible implementation:
Implementation
It has some nice definitional equality properties:
def Quotient.lift_attached_eq : ⟦x⟧.lift_attached f p = f x
:= rfl
def Quotient.lift_attached'_eq : ⟦x⟧.lift_attached' f p = f x
:= rfl
This looked pretty remarkable to me.
Eric Wieser (Jan 27 2025 at 09:38):
I think your first example can be shortened with docs#Quotient.recOnSubsingleton
mniip (Jan 27 2025 at 09:54):
Actually it's the implementation of Quotient.attach
that can be greatly simplified using recOnSubsingleton
indeed:
def Quotient.attach {r : Setoid α} (q : Quotient r) : Trunc { x // ⟦x⟧ = q }
:= q.recOnSubsingleton λx => Trunc.mk ⟨x, rfl⟩
mniip (Jan 27 2025 at 10:00):
I guess what my original implementation does is reinvent the dependent eliminator (Quotient.recOn
) in terms of the non-dependent eliminator (Quotient.lift
)...
Eric Wieser (Jan 27 2025 at 10:20):
Last updated: May 02 2025 at 03:31 UTC