-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathBasic.lean
More file actions
133 lines (105 loc) · 4.72 KB
/
Copy pathBasic.lean
File metadata and controls
133 lines (105 loc) · 4.72 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/-
Copyright (c) 2026 PolyFun Contributors. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Devon Tuma
-/
module
public import PolyFun.IPFunctor.Basic
/-!
# Lenses Between Indexed Polynomial Functors
A `Lens P Q` between two indexed polynomial functors `P Q : IPFunctor I J` is a Cartesian
morphism over the same input/output indices: a forward map on positions and a *backward* map
on responses, together with the *source-index preservation law* `src_eq` that says the two
child sources (computed via `P.src` after pulling back, or via `Q.src` directly) agree in `I`.
The `src_eq` law is equality of index *values* in `I`, not of types, so most concrete lenses
discharge it by `rfl`. In general it induces transports in object maps because children live
in fibers over `src ...`.
This file provides the basic structure plus identity, composition, and a structural-equivalence
companion (`Lens.Equiv`). The richer monoidal / distributive infrastructure of
[`PFunctor.Lens`](../../PFunctor/Lens/Basic.lean) is intentionally not mirrored here yet —
add operations on demand as downstream consumers need them.
-/
@[expose] public section
universe uI uJ uA uA₁ uA₂ uA₃ uA₄ uB uB₁ uB₂ uB₃ uB₄
namespace IPFunctor
variable {I : Type uI} {J : Type uJ}
/-- A **lens** between indexed polynomial functors `P Q : IPFunctor I J`: a forward map on
positions, a backward map on responses, and the source-index preservation law `src_eq`. -/
structure Lens (P : IPFunctor.{uI, uJ, uA₁, uB₁} I J) (Q : IPFunctor.{uI, uJ, uA₂, uB₂} I J) where
/-- Forward map on positions, indexed by the output index `j : J`. -/
toFunA : ∀ j, P.A j → Q.A j
/-- Backward map on responses: a `Q`-response at `toFunA j a` pulls back to a `P`-response
at the original shape `a`. -/
toFunB : ∀ j a, Q.B j (toFunA j a) → P.B j a
/-- Source-index preservation: the pulled-back child source agrees with the original. -/
src_eq : ∀ j a d, P.src j a (toFunB j a d) = Q.src j (toFunA j a) d
namespace Lens
/-- The identity lens. -/
protected def id (P : IPFunctor.{uI, uJ, uA, uB} I J) : Lens P P where
toFunA _ := id
toFunB _ _ := id
src_eq _ _ _ := rfl
/-- Composition of lenses in function-composition order: `l ∘ₗ l'` applies `l'` first,
then `l`. -/
def comp {P : IPFunctor.{uI, uJ, uA₁, uB₁} I J} {Q : IPFunctor.{uI, uJ, uA₂, uB₂} I J}
{R : IPFunctor.{uI, uJ, uA₃, uB₃} I J} (l : Lens Q R) (l' : Lens P Q) : Lens P R where
toFunA j := l.toFunA j ∘ l'.toFunA j
toFunB j a := l'.toFunB j a ∘ l.toFunB j (l'.toFunA j a)
src_eq j a d := by
simp [l'.src_eq, l.src_eq]
@[inherit_doc] scoped infixl:75 " ∘ₗ " => IPFunctor.Lens.comp
variable {P : IPFunctor.{uI, uJ, uA₁, uB₁} I J}
{Q : IPFunctor.{uI, uJ, uA₂, uB₂} I J}
{R : IPFunctor.{uI, uJ, uA₃, uB₃} I J}
{S : IPFunctor.{uI, uJ, uA₄, uB₄} I J}
@[simp]
theorem id_comp (f : Lens P Q) : (Lens.id Q) ∘ₗ f = f := rfl
@[simp]
theorem comp_id (f : Lens P Q) : f ∘ₗ (Lens.id P) = f := rfl
theorem comp_assoc (l : Lens R S) (l' : Lens Q R) (l'' : Lens P Q) :
(l ∘ₗ l') ∘ₗ l'' = l ∘ₗ (l' ∘ₗ l'') := rfl
/-! ## Equivalence (isomorphism in the lens category) -/
/-- A structural equivalence in the lens category: a pair of lenses that compose to identity
in both directions. -/
@[ext]
structure Equiv (P : IPFunctor.{uI, uJ, uA₁, uB₁} I J) (Q : IPFunctor.{uI, uJ, uA₂, uB₂} I J) where
/-- The forward lens. -/
toLens : Lens P Q
/-- The inverse lens. -/
invLens : Lens Q P
/-- Round-trip on `P`. -/
left_inv : invLens ∘ₗ toLens = Lens.id P
/-- Round-trip on `Q`. -/
right_inv : toLens ∘ₗ invLens = Lens.id Q
@[inherit_doc] scoped infix:50 " ≃ₗ " => IPFunctor.Lens.Equiv
namespace Equiv
/-- The identity equivalence on `P`, built from the identity lens in both directions. -/
@[refl]
def refl (P : IPFunctor.{uI, uJ, uA, uB} I J) : P ≃ₗ P where
toLens := Lens.id P
invLens := Lens.id P
left_inv := rfl
right_inv := rfl
/-- The inverse of an equivalence, swapping the forward and inverse lenses. -/
@[symm]
def symm (e : P ≃ₗ Q) : Q ≃ₗ P where
toLens := e.invLens
invLens := e.toLens
left_inv := e.right_inv
right_inv := e.left_inv
/-- Composition of equivalences, composing the forward and inverse lenses respectively. -/
@[trans]
def trans (e₁ : P ≃ₗ Q) (e₂ : Q ≃ₗ R) : P ≃ₗ R where
toLens := e₂.toLens ∘ₗ e₁.toLens
invLens := e₁.invLens ∘ₗ e₂.invLens
left_inv := by
rw [comp_assoc]
rw (occs := [2]) [← comp_assoc]
simp [e₁.left_inv, e₂.left_inv]
right_inv := by
rw [comp_assoc]
rw (occs := [2]) [← comp_assoc]
simp [e₁.right_inv, e₂.right_inv]
end Equiv
end Lens
end IPFunctor