0 | ||| This module defines profunctor strength with respect to a particular
  1 | ||| monoidal structure.
  2 | |||
  3 | ||| Unlike Haskell's profunctors library, `Strong` and `Choice` are here
  4 | ||| special cases of the interface `GenStrong`, which defines strength with
  5 | ||| respect to an arbitrary tensor product. When writing implementations for
  6 | ||| a profunctor, `GenStrong Pair` and `GenStrong Either` should be used instead
  7 | ||| of `Strong` and `Choice` respectively.
  8 | module Data.Profunctor.Strong
  9 |
 10 | import Data.Morphisms
 11 | import Data.Tensor
 12 | import Data.Profunctor.Functor
 13 | import Data.Profunctor.Types
 14 |
 15 | %default total
 16 |
 17 |
 18 | ------------------------------------------------------------------------------
 19 | -- Strength interface
 20 | ------------------------------------------------------------------------------
 21 |
 22 | ||| Profunctor strength with respect to a tensor product.
 23 | ||| A strong profunctor preserves the monoidal structure of a category.
 24 | |||
 25 | ||| These constraints are not required by the interface, but the tensor product
 26 | ||| `ten` is generally expected to implement `(Tensor ten i, Symmetric ten)`.
 27 | |||
 28 | ||| Laws:
 29 | ||| * `strongl = dimap swap' swap' . strongr`
 30 | ||| * `dimap unitr.rightToLeft unitr.leftToRight . strongl = id`
 31 | ||| * `lmap (mapSnd f) . strongl = rmap (mapSnd f) . strongl`
 32 | ||| * `strongr . strongr = dimap assocr assocl . strongr`
 33 | |||
 34 | ||| @ ten The tensor product of the monoidal structure
 35 | public export
 36 | interface Profunctor p => GenStrong (0 ten : Type -> Type -> Type) p where
 37 |   ||| The left action of a strong profunctor.
 38 |   strongl : p a b -> p (a `ten` c) (b `ten` c)
 39 |   ||| The right action of a strong profunctor.
 40 |   strongr : p a b -> p (c `ten` a) (c `ten` b)
 41 |
 42 |
 43 | ||| Profunctor strength with respect to the product (`Pair`).
 44 | public export
 45 | Strong : (p : Type -> Type -> Type) -> Type
 46 | Strong = GenStrong Pair
 47 |
 48 | ||| A special case of `strongl` with constraint `Strong`.
 49 | ||| This is useful if the typechecker has trouble inferring the tensor product.
 50 | %inline
 51 | public export
 52 | first : Strong p => p a b -> p (a, c) (b, c)
 53 | first = strongl {ten=Pair}
 54 |
 55 | ||| A special case of `strongr` with constraint `Strong`.
 56 | ||| This is useful if the typechecker has trouble inferring the tensor product.
 57 | %inline
 58 | public export
 59 | second : Strong p => p a b -> p (c, a) (c, b)
 60 | second = strongr {ten=Pair}
 61 |
 62 | ||| Profunctor strength with respect to the coproduct (`Either`).
 63 | public export
 64 | Choice : (p : Type -> Type -> Type) -> Type
 65 | Choice = GenStrong Either
 66 |
 67 | ||| A special case of `strongl` with constraint `Choice`.
 68 | ||| This is useful if the typechecker has trouble inferring the tensor product to use.
 69 | %inline
 70 | public export
 71 | left : Choice p => p a b -> p (Either a c) (Either b c)
 72 | left = strongl {ten=Either}
 73 |
 74 | ||| A special case of `strongr` with constraint `Choice`.
 75 | ||| This is useful if the typechecker has trouble inferring the tensor product to use.
 76 | %inline
 77 | public export
 78 | right : Choice p => p a b -> p (Either c a) (Either c b)
 79 | right = strongr {ten=Either}
 80 |
 81 |
 82 | public export
 83 | uncurry' : Strong p => p a (b -> c) -> p (a, b) c
 84 | uncurry' = rmap (uncurry id) . first
 85 |
 86 | public export
 87 | strong : Strong p => (a -> b -> c) -> p a b -> p a c
 88 | strong f = dimap dup (uncurry $ flip f) . first
 89 |
 90 |
 91 | ------------------------------------------------------------------------------
 92 | -- Implementations
 93 | ------------------------------------------------------------------------------
 94 |
 95 |
 96 | public export
 97 | Bifunctor ten => GenStrong ten Morphism where
 98 |   strongl (Mor f) = Mor (mapFst f)
 99 |   strongr (Mor f) = Mor (mapSnd f)
100 |
101 | ||| A named implementation of `GenStrong` for function types.
102 | ||| Use this to avoid having to use a type wrapper like `Morphism`.
103 | public export
104 | [Function] Bifunctor ten => GenStrong ten (\a,b => a -> b)
105 |     using Profunctor.Function where
106 |   strongl = mapFst
107 |   strongr = mapSnd
108 |
109 | public export
110 | Functor f => GenStrong Pair (Kleislimorphism f) where
111 |   strongl (Kleisli f) = Kleisli $ \(a,c) => (,c) <$> f a
112 |   strongr (Kleisli f) = Kleisli $ \(c,a) => (c,) <$> f a
113 |
114 | public export
115 | Applicative f => GenStrong Either (Kleislimorphism f) where
116 |   strongl (Kleisli f) = Kleisli $ either (map Left . f) (pure . Right)
117 |   strongr (Kleisli f) = Kleisli $ either (pure . Left) (map Right . f)
118 |
119 | public export
120 | Functor f => GenStrong Pair (Star f) where
121 |   strongl (MkStar f) = MkStar $ \(a,c) => (,c) <$> f a
122 |   strongr (MkStar f) = MkStar $ \(c,a) => (c,) <$> f a
123 |
124 | public export
125 | Applicative f => GenStrong Either (Star f) where
126 |   strongl (MkStar f) = MkStar $ either (map Left . f) (pure . Right)
127 |   strongr (MkStar f) = MkStar $ either (pure . Left) (map Right . f)
128 |
129 | public export
130 | GenStrong Either Tagged where
131 |   strongl (Tag x) = Tag (Left x)
132 |   strongr (Tag x) = Tag (Right x)
133 |
134 | public export
135 | GenStrong Pair (Forget r) where
136 |   strongl (MkForget k) = MkForget (k . fst)
137 |   strongr (MkForget k) = MkForget (k . snd)
138 |
139 | public export
140 | Monoid r => GenStrong Either (Forget r) where
141 |   strongl (MkForget k) = MkForget (either k (const neutral))
142 |   strongr (MkForget k) = MkForget (either (const neutral) k)
143 |
144 | public export
145 | GenStrong Either (Coforget r) where
146 |   strongl (MkCoforget k) = MkCoforget (Left . k)
147 |   strongr (MkCoforget k) = MkCoforget (Right . k)
148 |
149 |
150 | ------------------------------------------------------------------------------
151 | -- Tambara
152 | ------------------------------------------------------------------------------
153 |
154 |
155 | ||| The comonad generated by the reflective subcategory of profunctors that
156 | ||| implement `GenStrong ten`.
157 | public export
158 | record GenTambara (ten, p : Type -> Type -> Type) a b where
159 |   constructor MkTambara
160 |   runTambara : forall c. p (a `ten` c) (b `ten` c)
161 |
162 | public export
163 | Bifunctor ten => Profunctor p => Profunctor (GenTambara ten p) where
164 |   dimap f g (MkTambara p) = MkTambara $ dimap (mapFst f) (mapFst g) p
165 |
166 | public export
167 | ProfunctorFunctor (GenTambara ten) where
168 |   promap f (MkTambara p) = MkTambara (f p)
169 |
170 | public export
171 | Tensor ten i => ProfunctorComonad (GenTambara ten) where
172 |   proextract (MkTambara p) = dimap unitr.rightToLeft unitr.leftToRight p
173 |   produplicate (MkTambara p) = MkTambara $ MkTambara $ dimap assocr assocl p
174 |
175 | public export
176 | Associative ten => Symmetric ten => Profunctor p => GenStrong ten (GenTambara ten p) where
177 |   strongl (MkTambara p) = MkTambara $ dimap assocr assocl p
178 |   strongr (MkTambara p) = MkTambara $ dimap (assocr . mapFst swap')
179 |                                             (mapFst swap' . assocl) p
180 |
181 | public export
182 | Bifunctor ten => Profunctor p => Functor (GenTambara ten p a) where
183 |   map = rmap
184 |
185 |
186 | ||| The comonad generated by the reflective subcategory of profunctors that
187 | ||| implement `Strong`.
188 | |||
189 | ||| This is a special case of `GenTambara`.
190 | public export
191 | Tambara : (p : Type -> Type -> Type) -> Type -> Type -> Type
192 | Tambara = GenTambara Pair
193 |
194 | ||| The comonad generated by the reflective subcategory of profunctors that
195 | ||| implement `Choice`.
196 | |||
197 | ||| This is a special case of `GenTambara`.
198 | public export
199 | TambaraSum : (p : Type -> Type -> Type) -> Type -> Type -> Type
200 | TambaraSum = GenTambara Either
201 |
202 |
203 | public export
204 | tambara : GenStrong ten p => p :-> q -> p :-> GenTambara ten q
205 | tambara @{gs} f x = MkTambara $ f $ strongl @{gs} x
206 |
207 | public export
208 | untambara : Tensor ten i => Profunctor q => p :-> GenTambara ten q -> p :-> q
209 | untambara f x = dimap unitr.rightToLeft unitr.leftToRight $ runTambara $ f x
210 |
211 |
212 | ------------------------------------------------------------------------------
213 | -- Pastro
214 | ------------------------------------------------------------------------------
215 |
216 |
217 | ||| The monad generated by the reflective subcategory of profunctors that
218 | ||| implement `GenStrong ten`.
219 | public export
220 | data GenPastro : (ten, p : Type -> Type -> Type) -> Type -> Type -> Type where
221 |   MkPastro : (y `ten` z -> b) -> p x y -> (a -> x `ten` z) -> GenPastro ten p a b
222 |
223 |
224 | public export
225 | Profunctor (GenPastro ten p) where
226 |   dimap f g (MkPastro l m r) = MkPastro (g . l) m (r . f)
227 |   lmap f (MkPastro l m r) = MkPastro l m (r . f)
228 |   rmap g (MkPastro l m r) = MkPastro (g . l) m r
229 |
230 | public export
231 | ProfunctorFunctor (GenPastro ten) where
232 |   promap f (MkPastro l m r) = MkPastro l (f m) r
233 |
234 | public export
235 | (Tensor ten i, Symmetric ten) => ProfunctorMonad (GenPastro ten) where
236 |   propure x = MkPastro unitr.leftToRight x unitr.rightToLeft
237 |   projoin (MkPastro {x=x',y=y',z=z'} l' (MkPastro {x,y,z} l m r) r') = MkPastro ll m rr
238 |     where
239 |       ll : y `ten` (z' `ten` z) -> b
240 |       ll = l' . mapFst l . assocl . mapSnd swap'
241 |
242 |       rr : a -> x `ten` (z' `ten` z)
243 |       rr = mapSnd swap' . assocr . mapFst r . r'
244 |
245 | public export
246 | ProfunctorAdjunction (GenPastro ten) (GenTambara ten) where
247 |   prounit x = MkTambara (MkPastro id x id)
248 |   procounit (MkPastro l (MkTambara x) r) = dimap r l x
249 |
250 | public export
251 | (Associative ten, Symmetric ten) => GenStrong ten (GenPastro ten p) where
252 |   strongl (MkPastro {x,y,z} l m r) = MkPastro l' m r'
253 |     where
254 |       l' : y `ten` (z `ten` c) -> b `ten` c
255 |       l' = mapFst l . assocl
256 |       r' : a `ten` c -> x `ten` (z `ten` c)
257 |       r' = assocr . mapFst r
258 |   strongr (MkPastro {x,y,z} l m r) = MkPastro l' m r'
259 |     where
260 |       l' : y `ten` (c `ten` z) -> c `ten` b
261 |       l' = swap' . mapFst l . assocl . mapSnd swap'
262 |       r' : c `ten` a -> x `ten` (c `ten` z)
263 |       r' = mapSnd swap' . assocr . mapFst r . swap'
264 |
265 |
266 | ||| The monad generated by the reflective subcategory of profunctors that
267 | ||| implement `Strong`.
268 | |||
269 | ||| This is a special case of `GenPastro`.
270 | public export
271 | Pastro : (p : Type -> Type -> Type) -> Type -> Type -> Type
272 | Pastro = GenPastro Pair
273 |
274 | ||| The monad generated by the reflective subcategory of profunctors that
275 | ||| implement `Choice`.
276 | |||
277 | ||| This is a special case of `GenPastro`.
278 | public export
279 | PastroSum : (p : Type -> Type -> Type) -> Type -> Type -> Type
280 | PastroSum = GenPastro Either
281 |
282 |
283 | public export
284 | pastro : GenStrong ten q => p :-> q -> GenPastro ten p :-> q
285 | pastro @{gs} f (MkPastro l m r) = dimap r l (strongl @{gs} (f m))
286 |
287 | public export
288 | unpastro : Tensor ten i => GenPastro ten p :-> q -> p :-> q
289 | unpastro f x = f (MkPastro unitr.leftToRight x unitr.rightToLeft)
290 |
291 |