11/-
22Copyright (c) 2022 Kim Morrison. All rights reserved.
33Released under Apache 2.0 license as described in the file LICENSE.
4- Authors: Kim Morrison
4+ Authors: Kim Morrison, Robin Carlier
55-/
66import Mathlib.CategoryTheory.Functor.Basic
77import Mathlib.Lean.Meta.Simp
@@ -22,6 +22,9 @@ This is useful for generating lemmas which the simplifier can use even on expres
2222that are already right associated.
2323
2424There is also a term elaborator `reassoc_of% t` for use within proofs.
25+
26+ The `Mathlib.Tactic.CategoryTheory.IsoReassoc` extends `@[reassoc]` and `reassoc_of%`
27+ to support creating isomorphism reassociation lemmas.
2528-/
2629
2730open Lean Meta Elab Tactic
@@ -42,12 +45,12 @@ def categorySimp (e : Expr) : MetaM Simp.Result :=
4245 (config := { decide := false })
4346
4447/--
45- Given an equation `f = g` between morphisms `X ⟶ Y` in a category (possibly after a `∀` binder) ,
48+ Given an equation `f = g` between morphisms `X ⟶ Y` in a category,
4649produce the equation `∀ {Z} (h : Y ⟶ Z), f ≫ h = g ≫ h`,
4750but with compositions fully right associated and identities removed.
4851-/
49- def reassocExpr (e : Expr) : MetaM Expr := do
50- mapForallTelescope ( fun e => do simpType categorySimp (← mkAppM ``eq_whisker' #[e])) e
52+ def reassocExprHom (e : Expr) : MetaM Expr := do
53+ simpType categorySimp (← mkAppM ``eq_whisker' #[e])
5154
5255/--
5356Adding `@[reassoc]` to a lemma named `F` of shape `∀ .., f = g`, where `f g : X ⟶ Y` are
@@ -66,9 +69,44 @@ Note that if you want both the lemma and the reassociated lemma to be
6669`simp` lemmas, you should tag the lemma `@[reassoc (attr := simp)]`.
6770The variant `@[simp, reassoc]` on a lemma `F` will tag `F` with `@[simp]`,
6871but not `F_assoc` (this is sometimes useful).
72+
73+ This attribute also works for lemmas of shape `∀ .., f = g` where `f g : X ≅ Y` are
74+ isomorphisms, provided that `Tactic.CategoryTheory.IsoReassoc` has been imported.
6975-/
7076syntax (name := reassoc) "reassoc" (" (" &"attr" " := " Parser.Term.attrInstance,* ")" )? : attr
7177
78+ /--
79+ IO ref for reassociation handlers `reassoc` attribute, so that it can be extended
80+ with additional handlers. Handlers take a proof of the equation.
81+
82+ The default handler is `reassocExprHom` for morphism reassociation.
83+ This will be extended in `Tactic.CategoryTheory.IsoReassoc` for isomorphism reassociation.
84+ -/
85+ private initialize reassocImplRef : IO.Ref (Array (Expr → MetaM Expr)) ← IO.mkRef #[]
86+
87+ /--
88+ Registers a handler for `reassocExpr`. The handler takes a proof of an equation
89+ and returns a proof of the reassociation lemma.
90+ Handlers are considered in order of registration.
91+ They are applied directly to the equation in the body of the forall.
92+ -/
93+ def registerReassocExpr (f : Expr → MetaM Expr) : IO Unit := do
94+ reassocImplRef.modify (·.push f)
95+
96+ initialize registerReassocExpr reassocExprHom
97+
98+ /--
99+ Reassociates the morphisms in `type?` using the registered handlers,
100+ using `reassocExprHom` as the default.
101+ If `type?` is not given, it is assumed to be the type of `pf`.
102+ -/
103+ def reassocExpr (pf : Expr) (type? : Option Expr) : MetaM Expr := do
104+ let pf ← if let some type := type? then mkExpectedTypeHint pf type else pure pf
105+ mapForallTelescope (forallTerm := pf) fun pf => do
106+ let handlers ← reassocImplRef.get
107+ handlers.firstM (fun h => h pf) <|> do
108+ throwError "`reassoc` can only be used on terms about equality of (iso)morphisms"
109+
72110initialize registerBuiltinAttribute {
73111 name := `reassoc
74112 descr := ""
@@ -78,17 +116,19 @@ initialize registerBuiltinAttribute {
78116 if (kind != AttributeKind.global) then
79117 throwError "`reassoc` can only be used as a global attribute"
80118 addRelatedDecl src "_assoc" ref stx? fun type value levels => do
81- pure (← reassocExpr (← mkExpectedTypeHint value type) , levels)
119+ pure (← reassocExpr value type, levels)
82120 | _ => throwUnsupportedSyntax }
83121
84- open Term in
85122/--
86123`reassoc_of% t`, where `t` is
87124an equation `f = g` between morphisms `X ⟶ Y` in a category (possibly after a `∀` binder),
88125produce the equation `∀ {Z} (h : Y ⟶ Z), f ≫ h = g ≫ h`,
89126but with compositions fully right associated and identities removed.
127+ This also works for equations between isomorphisms, provided that
128+ `Tactic.CategoryTheory.IsoReassoc` has been imported.
90129-/
91130elab "reassoc_of% " t:term : term => do
92- reassocExpr (← elabTerm t none)
131+ let e ← Term.elabTerm t none
132+ reassocExpr e none
93133
94134end CategoryTheory
0 commit comments