Module docstring
{"# Typeclass for a type F with an injective map to A → B
This typeclass is primarily for use by homomorphisms like MonoidHom and LinearMap.
There is the \"D\"ependent version DFunLike and the non-dependent version FunLike.
Basic usage of DFunLike and FunLike
A typical type of morphisms should be declared as: ``` structure MyHom (A B : Type*) [MyClass A] [MyClass B] where (toFun : A → B) (map_op' : ∀ (x y : A), toFun (MyClass.op x y) = MyClass.op (toFun x) (toFun y))
namespace MyHom
variable (A B : Type*) [MyClass A] [MyClass B]
instance : FunLike (MyHom A B) A B where coe := MyHom.toFun coe_injective' := fun f g h => by cases f; cases g; congr
@[ext] theorem ext {f g : MyHom A B} (h : ∀ x, f x = g x) : f = g := DFunLike.ext f g h
/-- Copy of a MyHom with a new toFun equal to the old one. Useful to fix definitional
equalities. -/
protected def copy (f : MyHom A B) (f' : A → B) (h : f' = ⇑f) : MyHom A B where
toFun := f'
mapop' := h.symm ▸ f.mapop'
end MyHom ```
This file will then provide a CoeFun instance and various
extensionality and simp lemmas.
Morphism classes extending DFunLike and FunLike
The FunLike design provides further benefits if you put in a bit more work.
The first step is to extend FunLike to create a class of those types satisfying
the axioms of your new type of morphisms.
Continuing the example above:
``
/--MyHomClass F A Bstates thatFis a type ofMyClass.op-preserving morphisms.
You should extend this class when you extendMyHom`. -/
class MyHomClass (F : Type) (A B : outParam Type) [MyClass A] [MyClass B]
[FunLike F A B] : Prop :=
(map_op : ∀ (f : F) (x y : A), f (MyClass.op x y) = MyClass.op (f x) (f y))
@[simp] lemma mapop {F A B : Type*} [MyClass A] [MyClass B] [FunLike F A B] [MyHomClass F A B] (f : F) (x y : A) : f (MyClass.op x y) = MyClass.op (f x) (f y) := MyHomClass.mapop _ _ _
-- You can add the below instance next to MyHomClass.instFunLike:
instance : MyHomClass (MyHom A B) A B where
mapop := MyHom.mapop'
-- [Insert ext and copy here]
```
Note that A B are marked as outParam even though they are not purely required to be so
due to the FunLike parameter already filling them in. This is required to see through
type synonyms, which is important in the category theory library. Also, it appears having them as
outParam is slightly faster.
The second step is to add instances of your new MyHomClass for all types extending MyHom.
Typically, you can just declare a new class analogous to MyHomClass:
``` structure CoolerHom (A B : Type*) [CoolClass A] [CoolClass B] extends MyHom A B where (map_cool' : toFun CoolClass.cool = CoolClass.cool)
class CoolerHomClass (F : Type) (A B : outParam Type) [CoolClass A] [CoolClass B] [FunLike F A B] extends MyHomClass F A B := (map_cool : ∀ (f : F), f CoolClass.cool = CoolClass.cool)
@[simp] lemma mapcool {F A B : Type*} [CoolClass A] [CoolClass B] [FunLike F A B] [CoolerHomClass F A B] (f : F) : f CoolClass.cool = CoolClass.cool := CoolerHomClass.mapcool _
variable {A B : Type*} [CoolClass A] [CoolClass B]
instance : FunLike (CoolerHom A B) A B where coe f := f.toFun coeinjective' := fun f g h ↦ by cases f; cases g; congr; apply DFunLike.coeinjective; congr
instance : CoolerHomClass (CoolerHom A B) A B where mapop f := f.mapop' mapcool f := f.mapcool'
-- [Insert ext and copy here]
```
Then any declaration taking a specific type of morphisms as parameter can instead take the
class you just defined:
-- Compare with: lemma do_something (f : MyHom A B) : sorry := sorry
lemma do_something {F : Type*} [FunLike F A B] [MyHomClass F A B] (f : F) : sorry :=
sorry
This means anything set up for MyHoms will automatically work for CoolerHomClasses,
and defining CoolerHomClass only takes a constant amount of effort,
instead of linearly increasing the work per MyHom-related declaration.
Design rationale
The current form of FunLike was set up in pull request https://github.com/leanprover-community/mathlib4/pull/8386:
https://github.com/leanprover-community/mathlib4/pull/8386
We made FunLike unbundled: child classes don't extend FunLike, they take a [FunLike F A B]
parameter instead. This suits the instance synthesis algorithm better: it's easy to verify a type
does not have a FunLike instance by checking the discrimination tree once instead of searching
the entire extends hierarchy.
","### DFunLike F α β where β depends on a : α ","### FunLike F α β where β does not depend on a : α "}