@@ -3,26 +3,46 @@
33[](https://travis-ci.org/kcsongor/generic-lens)
44[](https://hackage.haskell.org/package/generic-lens)
55
6−Generically derive lenses and prisms for data types.
6+Generically derive traversals, lenses and prisms.
77
88Available on [Hackage](https://hackage.haskell.org/package/generic-lens)
99
10+This library uses `GHC.Generics` to derive efficient optics (traversals, lenses
11+and prisms) for algebraic data types in a type-directed way, with a focus on
12+good type inference and error messages when possible.
13+
1014This package uses the GHC 8 `Generic` representation to derive various operations
1115on data structures with lens interfaces, including structural subtype
1216relationships between records and positional indexing into arbitrary product
1317types.
1418
15−This is made possible by GHC 8's new Generics API, which provides metadata
16−at the type-level (previously only value-level metadata was available).
19+The derived optics use the so-called van Laarhoven representation, thus are
20+fully interoperable with the combinators found in mainstream lens libraries.
21+
22+Examples can be found in the `examples` and `tests` folders.
23+
24+## Preliminaries
25+A typical module using `generic-lens` will usually have the following
26+extensions turned on:
27+```haskell
28+{-# LANGUAGE DataKinds #-}
29+{-# LANGUAGE DeriveGeneric #-}
30+{-# LANGUAGE DuplicateRecordFields #-}
31+{-# LANGUAGE NoMonomorphismRestriction #-}
32+{-# LANGUAGE TypeApplications #-}
33+```
1734
18−Examples can be found in the `examples` folder. This library makes heavy use of
19−[Visible Type Applications](https://ghc.haskell.org/trac/ghc/wiki/TypeApplication).
35+# Taxonomy of optics
36+Here is a comprehensive list of the optics exposed by `generic-lens`. The
37+combinators each allows a different way of identifying certain parts of
38+algebraic data types.
2039
2140## Lenses
2241
23−### Record fields
42+A lens identifies exactly one part of a product type, and allows querying and
43+updating it.
2444
25−Record fields can be accessed by their label:
45+### By name
2646
2747```haskell
2848data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
@@ -31,42 +51,74 @@ sally :: Person
3151sally = Person "Sally" 25
3252```
3353
34−```haskell
35−>>> getField @"age" sally
36−25
37−
38−>>> setField @"age" 26 sally
39−Person {name = "Sally", age = 26}
54+Record fields can be accessed by their label using the `field` lens.
4055
56+```haskell
4157>>> sally ^. field @"name"
4258"Sally"
4359
4460>>> sally & field @"name" .~ "Tamas"
4561Person {name = "Tamas", age = 25}
62+```
63+Here we use [visible type application](https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#visible-type-application)
64+to specify which field we're interested in, and use the `^.` and `.~` combinators from a lens library
65+([lens](https://hackage.haskell.org/package/lens), [microlens](https://hackage.haskell.org/package/microlens), etc.)
66+to query and update the field.
67+
68+Or for standalone use, the `getField` and `setField` functions can be used instead.
69+```haskell
70+>>> getField @"age" sally
71+25
72+
73+>>> setField @"age" 26 sally
74+Person {name = "Sally", age = 26}
75+```
4676
77+When a non-existent field is requested, the library generates a helpful type error:
78+```haskell
4779>>> sally ^. field @"pet"
4880error:
49− • The type Person does not contain a field named "pet"
81+ • The type Person does not contain a field named 'pet'
5082```
5183
52−If the accessed field is a type parameter that appears uniquely in the type,
53−then its type can be changed:
84+For types with multiple constructors, we can still use `field` as long as all constructors contain the required field
85+```haskell
86+data Two = First { wurble :: String, banana :: Int } | Second { wurble :: String } deriving (Generic, Show)
87+
88+>>> Second "woops" ^. field @"wurble"
89+"woops"
90+>>> Second "woops" ^. field @"banana"
91+ ...
92+ • Not all constructors of the type Two
93+ contain a field named 'banana'.
94+ The offending constructors are:
95+ • Second
96+ ...
97+```
98+
99+The type of `field` is
100+```haskell
101+field :: HasField name s t a b => Lens s t a b
102+```
103+Therefore it allows polymorphic (type-changing) updates, when the accessed field mentions type parameters.
54104
55105```haskell
56−data T a b c d = T
57− { paramA :: a
58− , paramB :: b
59− , paramC :: c
60− , paramD :: d
61− }
62− deriving (Generic, Show)
63−
64−>>> t = T "a" (10 :: Int) 'c' False
65−>>> t & field @"paramA" .~ 'a' & field @"paramB" .~ False
66−T {paramA = 'a', paramB = False, paramC = 'c', paramD = False}
106+data Foo f a = Foo
107+ { foo :: f a
108+ } deriving (Generic, Show)
109+
110+foo1 :: Foo Maybe Int
111+foo1 = Foo (Just 10)
112+
113+-- |
114+-- >>> foo2
115+-- Foo {foo = ["10"]}
116+foo2 :: Foo [] String
117+foo2 = foo1 & field @"foo" %~ (maybeToList . fmap show)
67118```
119+This example shows that higher-kinded parameters can also be changed (`Maybe` -> `[]`).
68120
69−### Positional fields
121+### By position
70122
71123Fields can be accessed by their position in the data structure (index starting at 1):
72124
@@ -79,12 +131,6 @@ polygon = Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 7 (-2))
79131```
80132
81133```haskell
82−>>> getPosition @2 polygon
83−Point 2 4 2
84−
85−>>> setPosition @1 (Point 26 5 3) polygon
86−Polygon (Point 26 5 3) (Point 2 4 2) (Point 5 7 (-2))
87−
88134>>> polygon ^. position @1 . position @2
891355
90136
@@ -96,49 +142,34 @@ error:
96142 • The type Polygon does not contain a field at position 10
97143```
98144
99−Since tuples are an instance of `Generic`, they also have positional lenses:
145+Since tuples are an instance of `Generic`, the positional lens readily works:
100146
101147```haskell
102148>>> (("hello", True), 5) ^. position @1 . position @2
103149True
150+>>> (("hello", True, "or"), 5, "even", "longer") ^. position @1 . position @2
151+True
104152```
105153
106−### Typed fields
154+### By type
107155
108156Fields can be accessed by their type in the data structure, assuming that this
109157type is unique:
110158
111159```haskell
112−data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
113−data Point = Point Int Int Int deriving (Generic, Show)
114−
115−sally :: Person
116−sally = Person "Sally" 25
117−
118−point :: Point
119−point = Point 1 2 3
120−```
121−
122−```haskell
123−>>> getTyped @String sally
160+>>> sally ^. typed @String
124161"Sally"
125162
126163>>> setTyped @Int sally 26
127164Person {name = "Sally", age = 26}
128−
129−>>> point ^. typed @Int
130−error:
131− • The type Point contains multiple values of type Int; the choice of value is thus ambiguous
132−
133−>>> point & typed @String .~ "Point"
134−error:
135− • The type Point does not contain a value of type [Char]
136165```
137166
138−### Structural subtyping
167+### By structure
139168
140−A record is a (structural) `subtype' of another, if its fields are a superset of
141−those of the other.
169+The `super` lens generalises the `field` lens to focus on a collection rather
170+than a single field.
171+We can say that a record is a (structural) `subtype' of another, if its fields
172+are a superset of those of the other.
142173
143174```haskell
144175data Human = Human
@@ -157,16 +188,10 @@ human = Human {name = "Tunyasz", age = 50, address = "London"}
157188```
158189
159190```haskell
160−
161−>>> upcast human :: Animal
191+>>> human ^. super @Animal
162192Animal {name = "Tunyasz", age = 50}
163193
164−-- 'smash' plug the smaller structure into the larger one
165−>>> smash (Animal "dog" 10) human
166−Human {name = "dog", age = 10, address = "London"}
167−
168−-- 'super' is a lens that focuses on a subrecord of a larger record:
169−>>> human ^. super @Animal
194+>>> upcast human :: Animal
170195Animal {name = "Tunyasz", age = 50}
171196```
172197
@@ -181,9 +206,35 @@ growUp (Animal name age) = Animal name (age + 50)
181206Human {name = "Tunyasz", age = 60, address = "London"}
182207```
183208
209+## Traversals
210+
211+Traversals allow multiple values to be queried or updated at the same time.
212+
213+### By type
214+```haskell
215+types :: HasTypes s a => Traversal s s a a
216+```
217+TODO.
218+
219+### By parameter
220+TODO.
221+```haskell
222+param :: HasParam pos s t a b => Traversal s t a b
223+```
224+
225+### By constraint
226+TODO.
227+```haskell
228+constraints :: HasConstraints c s t => Applicative g => (forall a b . c a b => a -> g b) -> s -> g t
229+```
230+
184231## Prisms
185232
186−### Named constructors
233+A prism focuses on one part of a sum type (which might not be present). Other
234+than querying the type, they can be "turned around" to inject the data into the
235+sum (like a constructor).
236+
237+### By name
187238
188239Constructor components can be accessed using the constructor's name:
189240
@@ -205,19 +256,20 @@ Just (MkDog {name = "Shep", age = 4})
205256
206257>>> shep ^? _Ctor @"Cat"
207258Nothing
259+```
208260
261+Constructors with multiple fields can be focused as a tuple
262+
263+```
209264>>> mog ^? _Ctor @"Cat"
210265Just ("Mog",5)
211266
212267>>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
213268Cat "Garfield" 6
214269
215−>>> donald ^? _Ctor @"Giraffe"
216−error:
217− • The type Animal does not contain a constructor named "Giraffe"
218270```
219271
220−### Typed constructors
272+### By type
221273
222274Constructor components can be accessed using the component's type, assuming
223275that this type is unique:
@@ -227,10 +279,10 @@ type Name = String
227279type Age = Int
228280
229281data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
230−data Animal = Dog Dog | Cat (Name, Age) | Duck Age deriving (Generic, Show)
282+data Animal = Dog Dog | Cat Name Age | Duck Age deriving (Generic, Show)
231283
232284shep = Dog (MkDog "Shep" 4)
233−mog = Cat ("Mog", 5)
285+mog = Cat "Mog" 5
234286donald = Duck 4
235287```
236288
@@ -244,6 +296,9 @@ Just (MkDog {name = "Shep", age = 4})
244296>>> donald ^? _Typed @Age
245297Just 4
246298
299+>>> mog ^? _Typed @(Name, Age)
300+("Mog", 5)
301+
247302>>> donald ^? _Typed @Float
248303error:
249304 • The type Animal does not contain a constructor whose field is of type Float