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):

(docs#Quotient.recOn)


Last updated: May 02 2025 at 03:31 UTC