Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Newer
Older
100644 447 lines (400 sloc) 16.759 kB
6be7786 @ekmett Factoring out Control.Lens.Type
authored
1 {-# LANGUAGE CPP #-}
2 {-# LANGUAGE GADTs #-}
3 {-# LANGUAGE Rank2Types #-}
4 {-# LANGUAGE FlexibleContexts #-}
5 {-# LANGUAGE FlexibleInstances #-}
6 {-# LANGUAGE ScopedTypeVariables #-}
7 {-# LANGUAGE MultiParamTypeClasses #-}
8 -------------------------------------------------------------------------------
9 -- |
10 -- Module : Control.Lens.Type
11 -- Copyright : (C) 2012 Edward Kmett
12 -- License : BSD-style (see the file LICENSE)
13 -- Maintainer : Edward Kmett <ekmett@gmail.com>
14 -- Stability : provisional
15 -- Portability : Rank2Types
16 --
17 -------------------------------------------------------------------------------
18 module Control.Lens.Type
19 (
20 -- * Lenses, Folds and Traversals
21 Lens, Lens'
22 , Traversal, Traversal'
23 , Iso, Iso'
24 , Prism , Prism'
25 , Setter, Setter'
26 , Getter
27 , Fold
28 , Action
29 , MonadicFold
30 -- * Indexed Variants
31 , IndexedLens, IndexedLens'
32 , IndexedTraversal, IndexedTraversal'
33 , IndexedSetter, IndexedSetter'
34 , IndexedGetter
35 , IndexedFold
36 , IndexedAction
37 , IndexedMonadicFold
38 -- * Common
39 , Simple
40 , LensLike, LensLike'
41 , IndexedLensLike, IndexedLensLike'
42 , Overloading, Overloading'
43 ) where
44
45 import Control.Applicative
46 import Control.Lens.Internal
47 import Data.Profunctor
48
49 -- $setup
50 -- >>> import Control.Lens
51 -- >>> import Debug.SimpleReflect.Expr
52 -- >>> import Debug.SimpleReflect.Vars as Vars hiding (f,g,h)
53 -- >>> let f :: Expr -> Expr; f = Debug.SimpleReflect.Vars.f
54 -- >>> let g :: Expr -> Expr; g = Debug.SimpleReflect.Vars.g
55 -- >>> let h :: Expr -> Expr -> Expr; h = Debug.SimpleReflect.Vars.h
56 -- >>> let getter :: Expr -> Expr; getter = fun "getter"
57 -- >>> let setter :: Expr -> Expr -> Expr; setter = fun "setter"
58
59 -------------------------------------------------------------------------------
60 -- Lenses
61 -------------------------------------------------------------------------------
62
63 -- | A 'Lens' is actually a lens family as described in
64 -- <http://comonad.com/reader/2012/mirrored-lenses/>.
65 --
66 -- With great power comes great responsibility and a 'Lens' is subject to the
67 -- three common sense lens laws:
68 --
69 -- 1) You get back what you put in:
70 --
71 -- @'Control.Lens.Getter.view' l ('Control.Lens.Setter.set' l b a) ≡ b@
72 --
73 -- 2) Putting back what you got doesn't change anything:
74 --
75 -- @'Control.Lens.Setter.set' l ('Control.Lens.Getter.view' l a) a ≡ a@
76 --
77 -- 3) Setting twice is the same as setting once:
78 --
79 -- @'Control.Lens.Setter.set' l c ('Control.Lens.Setter.set' l b a) ≡ 'Control.Lens.Setter.set' l c a@
80 --
81 -- These laws are strong enough that the 4 type parameters of a 'Lens' cannot
82 -- vary fully independently. For more on how they interact, read the \"Why is
83 -- it a Lens Family?\" section of
84 -- <http://comonad.com/reader/2012/mirrored-lenses/>.
85 --
86 -- Every 'Lens' can be used directly as a 'Control.Lens.Setter.Setter' or
87 -- 'Traversal'.
88 --
89 -- You can also use a 'Lens' for 'Control.Lens.Getter.Getting' as if it were a
90 -- 'Fold' or 'Getter'.
91 --
92 -- Since every lens is a valid 'Traversal', the
93 -- traversal laws are required of any lenses you create:
94 --
95 -- @
96 -- l 'pure' ≡ 'pure'
97 -- 'fmap' (l f) '.' l g ≡ 'Data.Functor.Compose.getCompose' '.' l ('Data.Functor.Compose.Compose' '.' 'fmap' f '.' g)
98 -- @
99 --
100 -- @type 'Lens' s t a b = forall f. 'Functor' f => 'LensLike' f s t a b@
101 type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
102
103 -- | @type 'Lens'' = 'Simple' 'Lens'@
104 type Lens' s a = Lens s s a a
105
106 ------------------------------------------------------------------------------
107 -- Indexed Lenses
108 ------------------------------------------------------------------------------
109
110 -- | Every 'IndexedLens' is a valid 'Lens' and a valid 'Control.Lens.Traversal.IndexedTraversal'.
111 type IndexedLens i s t a b = forall f p. (Indexable i p, Functor f) => p a (f b) -> s -> f t
112
113 -- | @type 'IndexedLens'' i = 'Simple' ('IndexedLens' i)@
114 type IndexedLens' i s a = IndexedLens i s s a a
115
116 ------------------------------------------------------------------------------
117 -- Traversals
118 ------------------------------------------------------------------------------
119
120 -- | A 'Traversal' can be used directly as a 'Control.Lens.Setter.Setter' or a 'Fold' (but not as a 'Lens') and provides
121 -- the ability to both read and update multiple fields, subject to some relatively weak 'Traversal' laws.
122 --
123 -- These have also been known as multilenses, but they have the signature and spirit of
124 --
125 -- @'traverse' :: 'Traversable' f => 'Traversal' (f a) (f b) a b@
126 --
127 -- and the more evocative name suggests their application.
128 --
129 -- Most of the time the 'Traversal' you will want to use is just 'traverse', but you can also pass any
130 -- 'Lens' or 'Iso' as a 'Traversal', and composition of a 'Traversal' (or 'Lens' or 'Iso') with a 'Traversal' (or 'Lens' or 'Iso')
131 -- using (.) forms a valid 'Traversal'.
132 --
133 -- The laws for a Traversal @t@ follow from the laws for Traversable as stated in \"The Essence of the Iterator Pattern\".
134 --
135 -- @
136 -- t 'pure' ≡ 'pure'
137 -- 'fmap' (t f) '.' t g ≡ 'Data.Functor.Compose.getCompose' '.' t ('Data.Functor.Compose.Compose' '.' 'fmap' f '.' g)
138 -- @
139 --
140 -- One consequence of this requirement is that a 'Traversal' needs to leave the same number of elements as a
141 -- candidate for subsequent 'Traversal' that it started with. Another testament to the strength of these laws
142 -- is that the caveat expressed in section 5.5 of the \"Essence of the Iterator Pattern\" about exotic
143 -- 'Traversable' instances that 'traverse' the same entry multiple times was actually already ruled out by the
144 -- second law in that same paper!
145 type Traversal s t a b = forall f. Applicative f => (a -> f b) -> s -> f t
146
147 -- | @type 'Traversal'' = 'Simple' 'Traversal'@
148 type Traversal' s a = Traversal s s a a
149
150 ------------------------------------------------------------------------------
151 -- Indexed Traversals
152 ------------------------------------------------------------------------------
153
154 -- | Every indexed traversal is a valid 'Control.Lens.Traversal.Traversal' or
155 -- 'Control.Lens.Fold.IndexedFold'.
156 --
157 -- The 'Indexed' constraint is used to allow an 'IndexedTraversal' to be used
158 -- directly as a 'Control.Lens.Traversal.Traversal'.
159 --
160 -- The 'Control.Lens.Traversal.Traversal' laws are still required to hold.
161 type IndexedTraversal i s t a b = forall f p. (Indexable i p, Applicative f) => p a (f b) -> s -> f t
162
163 -- | @type 'IndexedTraversal'' i = 'Simple' ('IndexedTraversal' i)@
164 type IndexedTraversal' i s a = IndexedTraversal i s s a a
165
166 ------------------------------------------------------------------------------
167 -- Setters
168 ------------------------------------------------------------------------------
169
170 -- |
171 -- The only 'Lens'-like law that can apply to a 'Setter' @l@ is that
172 --
173 -- @'set' l y ('set' l x a) ≡ 'set' l y a@
174 --
175 -- You can't 'view' a 'Setter' in general, so the other two laws are irrelevant.
176 --
177 -- However, two 'Functor' laws apply to a 'Setter':
178 --
179 -- @
180 -- 'over' l 'id' ≡ 'id'
181 -- 'over' l f '.' 'over' l g ≡ 'over' l (f '.' g)
182 -- @
183 --
184 -- These an be stated more directly:
185 --
186 -- @
187 -- l 'pure' ≡ 'pure'
188 -- l f . 'untainted' . l g ≡ l (f . 'untainted' . g)
189 -- @
190 --
191 -- You can compose a 'Setter' with a 'Lens' or a 'Traversal' using ('.') from the Prelude
192 -- and the result is always only a 'Setter' and nothing more.
193 --
194 -- >>> over traverse f [a,b,c,d]
195 -- [f a,f b,f c,f d]
196 --
197 -- >>> over _1 f (a,b)
198 -- (f a,b)
199 --
200 -- >>> over (traverse._1) f [(a,b),(c,d)]
201 -- [(f a,b),(f c,d)]
202 --
203 -- >>> over both f (a,b)
204 -- (f a,f b)
205 --
206 -- >>> over (traverse.both) f [(a,b),(c,d)]
207 -- [(f a,f b),(f c,f d)]
208 type Setter s t a b = forall f. Settable f => (a -> f b) -> s -> f t
209
210 -- |
211 --
212 -- A 'Setter'' is just a 'Setter' that doesn't change the types.
213 --
214 -- These are particularly common when talking about monomorphic containers. /e.g./
215 --
216 -- @'sets' Data.Text.map :: 'Setter'' 'Data.Text.Internal.Text' 'Char'@
217 --
218 -- @type 'Setter'' = 'Setter''@
219 type Setter' s a = Setter s s a a
220
221 -- | Every 'IndexedSetter' is a valid 'Setter'
222 --
223 -- The 'Setter' laws are still required to hold.
224 type IndexedSetter i s t a b = forall f p.
225 (Indexable i p, Settable f) => p a (f b) -> s -> f t
226
227 -- |
228 -- @type 'IndexedSetter'' i = 'Simple' ('IndexedSetter' i)@
229 type IndexedSetter' i s a = IndexedSetter i s s a a
230
231 -----------------------------------------------------------------------------
232 -- Isomorphisms
233 -----------------------------------------------------------------------------
234
235 -- | Isomorphism families can be composed with other lenses using ('.') and 'id'.
236 type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)
237
238 -- |
239 -- @type 'Iso'' = 'Control.Lens.Type.Simple' 'Iso'@
240 type Iso' s a = Iso s s a a
241
242 ------------------------------------------------------------------------------
243 -- Prism Internals
244 ------------------------------------------------------------------------------
245
246 -- | A 'Prism' @l@ is a 0-or-1 target 'Traversal' that can also be turned around with 'remit' to
247 -- obtain a 'Getter' in the opposite direction.
248 --
249 -- There are two laws that a 'Prism' should satisfy:
250 --
251 -- First, if I 'remit' or 'Control.Lens.Prism.review' a value with a 'Prism' and then 'Control.Lens.Prism.preview' or use ('^?'), I will get it back:
252 --
253 -- * @'Control.Lens.Prism.preview' l ('Control.Lens.Prism.review' l b) ≡ 'Just' b@
254 --
255 -- Second, if you can extract a value @a@ using a Prism @l@ from a value @s@, then the value @s@ is completely described my @l@ and @a@:
256 --
257 -- * If @'Control.Lens.Prism.preview' l s ≡ 'Just' a@ then @'Control.Lens.Prism.review' l a ≡ s@
258 --
259 -- These two laws imply that the 'Traversal' laws hold for every 'Prism' and that we 'traverse' at most 1 element:
260 --
261 -- @'Control.Lens.Fold.lengthOf' l x '<=' 1@
262 --
263 -- It may help to think of this as a 'Iso' that can be partial in one direction.
264 --
265 -- Every 'Prism' is a valid 'Traversal'.
266 --
267 -- Every 'Iso' is a valid 'Prism'.
268 --
269 -- For example, you might have a @'Prism'' 'Integer' Natural@ allows you to always
270 -- go from a 'Natural' to an 'Integer', and provide you with tools to check if an 'Integer' is
271 -- a 'Natural' and/or to edit one if it is.
272 --
273 --
274 -- @
275 -- 'nat' :: 'Prism'' 'Integer' 'Numeric.Natural.Natural'
276 -- 'nat' = 'prism' 'toInteger' '$' \\ i ->
277 -- if i '<' 0
278 -- then 'Left' i
279 -- else 'Right' ('fromInteger' i)
280 -- @
281 --
282 -- Now we can ask if an 'Integer' is a 'Natural'.
283 --
284 -- >>> 5^?nat
285 -- Just 5
286 --
287 -- >>> (-5)^?nat
288 -- Nothing
289 --
290 -- We can update the ones that are:
291 --
292 -- >>> (-3,4) & both.nat *~ 2
293 -- (-3,8)
294 --
295 -- And we can then convert from a 'Natural' to an 'Integer'.
296 --
297 -- >>> 5 ^. remit nat -- :: Natural
298 -- 5
299 --
300 -- Similarly we can use a 'Prism' to 'traverse' the left half of an 'Either':
301 --
302 -- >>> Left "hello" & _left %~ length
303 -- Left 5
304 --
305 -- or to construct an 'Either':
306 --
307 -- >>> 5^.remit _left
308 -- Left 5
309 --
310 -- such that if you query it with the 'Prism', you will get your original input back.
311 --
312 -- >>> 5^.remit _left ^? _left
313 -- Just 5
314 --
315 -- Another interesting way to think of a 'Prism' is as the categorical dual of a 'Lens'
316 -- -- a /co/-'Lens', so to speak. This is what permits the construction of 'outside'.
317 type Prism s t a b = forall p f. (Prismatic p, Applicative f) => p a (f b) -> p s (f t)
318
319 -- | A 'Simple' 'Prism'
320 type Prism' s a = Prism s s a a
321
322 -------------------------------------------------------------------------------
323 -- Getters
324 -------------------------------------------------------------------------------
325
326 -- | A 'Getter' describes how to retrieve a single value in a way that can be
327 -- composed with other lens-like constructions.
328 --
329 -- Unlike a 'Lens' a 'Getter' is read-only. Since a 'Getter'
330 -- cannot be used to write back there are no lens laws that can be applied to
331 -- it. In fact, it is isomorphic to an arbitrary function from @(a -> s)@.
332 --
333 -- Moreover, a 'Getter' can be used directly as a 'Control.Lens.Fold.Fold',
334 -- since it just ignores the 'Applicative'.
335 type Getter s a = forall f. Gettable f => (a -> f a) -> s -> f s
336
337 -- | Every 'IndexedGetter' is a valid 'Control.Lens.Fold.IndexedFold' and 'Getter'.
338 type IndexedGetter i s a = forall p f. (Indexable i p, Gettable f) => p a (f a) -> s -> f s
339
340 --------------------------
341 -- Folds
342 --------------------------
343
344 -- | A 'Fold' describes how to retrieve multiple values in a way that can be composed
345 -- with other lens-like constructions.
346 --
347 -- A @'Fold' s a@ provides a structure with operations very similar to those of the 'Foldable'
348 -- typeclass, see 'foldMapOf' and the other 'Fold' combinators.
349 --
350 -- By convention, if there exists a 'foo' method that expects a @'Foldable' (f a)@, then there should be a
351 -- @fooOf@ method that takes a @'Fold' s a@ and a value of type @s@.
352 --
353 -- A 'Getter' is a legal 'Fold' that just ignores the supplied 'Monoid'
354 --
355 -- Unlike a 'Control.Lens.Traversal.Traversal' a 'Fold' is read-only. Since a 'Fold' cannot be used to write back
356 -- there are no lens laws that apply.
357 type Fold s a = forall f. (Gettable f, Applicative f) => (a -> f a) -> s -> f s
358
359 -- | Every 'IndexedFold' is a valid 'Control.Lens.Fold.Fold'.
360 type IndexedFold i s a = forall p f.
361 (Indexable i p, Applicative f, Gettable f) => p a (f a) -> s -> f s
362
363 -------------------------------------------------------------------------------
364 -- Actions
365 -------------------------------------------------------------------------------
366
367 -- | An 'Action' is a 'Getter' enriched with access to a 'Monad' for side-effects.
368 --
369 -- Every 'Getter' can be used as an 'Action'
370 --
371 -- You can compose an 'Action' with another 'Action' using ('Prelude..') from the @Prelude@.
372 type Action m s a = forall f r. Effective m r f => (a -> f a) -> s -> f s
373
374 -- | An 'IndexedAction' is an 'IndexedGetter' enriched with access to a 'Monad' for side-effects.
375 --
376 -- Every 'Getter' can be used as an 'Action'
377 --
378 -- You can compose an 'Action' with another 'Action' using ('Prelude..') from the @Prelude@.
379 type IndexedAction i m s a = forall p f r. (Indexable i p, Effective m r f) => p a (f a) -> s -> f s
380
381 -------------------------------------------------------------------------------
382 -- MonadicFolds
383 -------------------------------------------------------------------------------
384
385 -- | A 'MonadicFold' is a 'Fold' enriched with access to a 'Monad' for side-effects.
386 --
387 -- Every 'Fold' can be used as a 'MonadicFold', that simply ignores the access to the 'Monad'.
388 --
389 -- You can compose a 'MonadicFold' with another 'MonadicFold' using ('Prelude..') from the @Prelude@.
390 type MonadicFold m s a = forall f r. (Effective m r f, Applicative f) => (a -> f a) -> s -> f s
391
392 -- | An 'IndexedMonadicFold' is an 'IndexedFold' enriched with access to a 'Monad' for side-effects.
393 --
394 -- Every 'IndexedFold' can be used as an 'IndexedMonadicFold', that simply ignores the access to the 'Monad'.
395 --
396 -- You can compose an 'IndexedMonadicFold' with another 'IndexedMonadicFold' using ('Prelude..') from the @Prelude@.
397 type IndexedMonadicFold i m s a = forall p f r. (Indexable i p, Effective m r f, Applicative f) => p a (f a) -> s -> f s
398
399 -------------------------------------------------------------------------------
400 -- Simple Overloading
401 -------------------------------------------------------------------------------
402
403 -- | A 'Simple' 'Lens', 'Simple' 'Traversal', ... can
404 -- be used instead of a 'Lens','Traversal', ...
405 -- whenever the type variables don't change upon setting a value.
406 --
407 -- @
408 -- 'Data.Complex.Lens.imaginary' :: 'Simple' 'Lens' ('Data.Complex.Complex' a) a
409 -- 'Data.List.Lens.traverseHead' :: 'Simple' 'Traversal' [a] a
410 -- @
411 --
412 -- Note: To use this alias in your own code with @'LensLike' f@ or
413 -- 'Setter', you may have to turn on @LiberalTypeSynonyms@.
414 --
415 -- This is commonly abbreviated as a \"prime\" marker, /e.g./ 'Lens'' = 'Simple' 'Lens'.
416 type Simple f s a = f s s a a
417
418 -- | @type 'LensLike' f s t a b = 'Overloading' (->) (->) f s t a b@
419 type Overloading p q f s t a b = p a (f b) -> q s (f t)
420
421 -- | @type 'Overloading'' p q f s a = 'Simple' ('Overloading' p q f) s a@
422 type Overloading' p q f s a = Overloading p q f s s a a
423
424 -- |
425 -- Many combinators that accept a 'Lens' can also accept a
426 -- 'Traversal' in limited situations.
427 --
428 -- They do so by specializing the type of 'Functor' that they require of the
429 -- caller.
430 --
431 -- If a function accepts a @'LensLike' f s t a b@ for some 'Functor' @f@,
432 -- then they may be passed a 'Lens'.
433 --
434 -- Further, if @f@ is an 'Applicative', they may also be passed a
435 -- 'Traversal'.
436 type LensLike f s t a b = (a -> f b) -> s -> f t
437
438 -- | @type 'LensLike'' f = 'Simple' ('LensLike' f)@
439 type LensLike' f s a = LensLike f s s a a
440
441 -- | Convenient alias for constructing indexed lenses and their ilk
442 type IndexedLensLike p f s t a b = p a (f b) -> s -> f t
443
444 -- | Convenient alias for constructing simple indexed lenses and their ilk
445 type IndexedLensLike' p f s a = p a (f a) -> s -> f s
446
Something went wrong with that request. Please try again.