on master help sign in
Squashed commit of the following:
f7fd419Csongor Kiss
README.md+130−21
@@ -3,25 +3,29 @@
3[![Build
3[![Build
4Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
4Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
5
5
6−Generically derive lenses for accessing fields of data types.
6+Generically derive lenses and prisms for data types.
7
7
8Available on [Hackage](https://hackage.haskell.org/package/generic-lens)
8Available on [Hackage](https://hackage.haskell.org/package/generic-lens)
9
9
10−This package uses the GHC 8 Generic representation to derive various operations on data structures with a lens interface, including structural subtype relationship between records and positional indexing into arbitrary product types.
10+This package uses the GHC 8 `Generic` representation to derive various operations
11+on data structures with lens interfaces, including structural subtype
12+relationships between records and positional indexing into arbitrary product
13+types.
11
14
12−This is made possible by GHC-8's new Generics API, which provides the meta-data
15+This is made possible by GHC 8's new Generics API, which provides metadata
13−at the type-level (previously only value-level meta-data was available).
16+at the type-level (previously only value-level metadata was available).
14
17
15−An example can be found in the `examples` folder.
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).
16
20
17−(The library makes heavy use of [Visible Type Applications](https://ghc.haskell.org/trac/ghc/wiki/TypeApplication))
21+## Lenses
18
22
19−## Record fields
23+### Record fields
20
24
21−Record fields can be accessed by their label.
25+Record fields can be accessed by their label:
22
26
23```haskell
27```haskell
24−data Person = Person { name :: String, age :: Int } deriving (Show, Generic)
28+data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
25
29
26sally :: Person
30sally :: Person
27sally = Person "Sally" 25
31sally = Person "Sally" 25
@@ -32,30 +36,32 @@ sally = Person "Sally" 25
3225
3625
33
37
34>>> setField @"age" 26 sally
38>>> setField @"age" 26 sally
35−Person { name = "Sally", age = 26 }
39+Person {name = "Sally", age = 26}
36
40
37>>> sally ^. field @"name"
41>>> sally ^. field @"name"
38"Sally"
42"Sally"
39
43
40>>> sally & field @"name" .~ "Tamas"
44>>> sally & field @"name" .~ "Tamas"
41−Person { name = "Tamas", age = 25 }
45+Person {name = "Tamas", age = 25}
42
46
47+>>> sally ^. field @"pet"
48+error:
49+ • The type Person does not contain a field named "pet"
43```
50```
44
51
45−## Positional fields
52+### Positional fields
46
53
47−Fields can be accessed by their position in the data structure (index starting at 1).
54+Fields can be accessed by their position in the data structure (index starting at 1):
48
55
49```haskell
56```haskell
50−data Point = Point Int Int Int deriving (Show, Generic)
57+data Point = Point Int Int Int deriving (Generic, Show)
51−data Polygon = Polygon Point Point Point deriving (Show, Generic)
58+data Polygon = Polygon Point Point Point deriving (Generic, Show)
52
59
53polygon :: Polygon
60polygon :: Polygon
54polygon = Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 7 (-2))
61polygon = Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 7 (-2))
55```
62```
56
63
57```haskell
64```haskell
58−
59>>> getPosition @2 polygon
65>>> getPosition @2 polygon
60Point 2 4 2
66Point 2 4 2
61
67
@@ -68,19 +74,51 @@ Polygon (Point 26 5 3) (Point 2 4 2) (Point 5 7 (-2))
68>>> polygon & position @3 . position @2 %~ (+10)
74>>> polygon & position @3 . position @2 %~ (+10)
69Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 17 (-2))
75Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 17 (-2))
70
76
77+>>> polygon ^. position @10
78+error:
79+ • The type Polygon does not contain a field at position 10
71```
80```
72
81
73−Since tuples are an instance of Generic, positional lenses can be used with them.
82+Since tuples are an instance of `Generic`, they also have positional lenses:
74
83
75```haskell
84```haskell
76>>> (("hello", True), 5) ^. position @1 . position @2
85>>> (("hello", True), 5) ^. position @1 . position @2
77True
86True
78```
87```
79
88
80−## Typed fields
89+### Typed fields
81−- TODO
90+
91+Fields can be accessed by their type in the data structure, assuming that this
92+type is unique:
93+
94+```haskell
95+data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
96+data Point = Point Int Int Int deriving (Generic, Show)
97+
98+sally :: Person
99+sally = Person "Sally" 25
100+
101+point :: Point
102+point = Point 1 2 3
103+```
104+
105+```haskell
106+>>> getTyped @String sally
107+"Sally"
82
108
109+>>> setTyped @Int sally 26
110+Person {name = "Sally", age = 26}
111+
112+>>> point ^. typed @Int
113+error:
114+ • The type Point contains multiple values of type Int; the choice of value is thus ambiguous
115+
116+>>> point & typed @String .~ "Point"
117+error:
118+ • The type Point does not contain a value of type [Char]
119+```
120+
83−## Structural subtyping
121+### Structural subtyping
84
122
85A record is a (structural) `subtype' of another, if its fields are a superset of
123A record is a (structural) `subtype' of another, if its fields are a superset of
86those of the other.
124those of the other.
@@ -98,7 +136,7 @@ data Animal = Animal
98 } deriving (Generic, Show)
136 } deriving (Generic, Show)
99
137
100human :: Human
138human :: Human
101−human = Human { name = "Tunyasz", age = 50, address = "London" }
139+human = Human {name = "Tunyasz", age = 50, address = "London"}
102```
140```
103
141
104```haskell
142```haskell
@@ -126,6 +164,77 @@ growUp (Animal name age) = Animal name (age + 50)
126Human {name = "Tunyasz", age = 60, address = "London"}
164Human {name = "Tunyasz", age = 60, address = "London"}
127```
165```
128
166
167+## Prisms
168+
169+### Named constructors
170+
171+Constructor components can be accessed using the constructor's name:
172+
173+```haskell
174+type Name = String
175+type Age = Int
176+
177+data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
178+data Animal = Dog Dog | Cat (Name, Age) | Duck Age deriving (Generic, Show)
179+
180+shep = Dog (MkDog "Shep" 4)
181+mog = Cat ("Mog", 5)
182+donald = Duck 4
183+```
184+
185+```haskell
186+>>> shep ^? _Ctor @"Dog"
187+Just (MkDog {name = "Shep", age = 4})
188+
189+>>> shep ^? _Ctor @"Cat"
190+Nothing
191+
192+>>> mog ^? _Ctor @"Cat"
193+Just ("Mog",5)
194+
195+>>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
196+Cat ("Garfield",6)
197+
198+>>> donald ^? _Ctor @"Giraffe"
199+error:
200+ • The type Animal does not contain a constructor named "Giraffe"
201+```
202+
203+## Typed constructors
204+
205+Constructor components can be accessed using the component's type, assuming
206+that this type is unique:
207+
208+```haskell
209+type Name = String
210+type Age = Int
211+
212+data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
213+data Animal = Dog Dog | Cat (Name, Age) | Duck Age deriving (Generic, Show)
214+
215+shep = Dog (MkDog "Shep" 4)
216+mog = Cat ("Mog", 5)
217+donald = Duck 4
218+```
219+
220+```haskell
221+>>> mog ^? _Typed @Dog
222+Nothing
223+
224+>>> shep ^? _Typed @Dog
225+Just (MkDog {name = "Shep", age = 4})
226+
227+>>> donald ^? _Typed @Age
228+Just 4
229+
230+>>> donald ^? _Typed @Float
231+error:
232+ • The type Animal does not contain a constructor whose field is of type Float
233+
234+>>> _Typed @Age # 6 :: Animal
235+Duck 6
236+```
237+
129## Contributors
238## Contributors
130
239
131+ [Toby Shaw](https://github.com/TobyShaw)
240+ [Toby Shaw](https://github.com/TobyShaw)
src/Data/Generics/Internal/Families/Has.hs+1−2
@@ -11,11 +11,10 @@ module Data.Generics.Internal.Families.Has
11 , HasCtorP
11 , HasCtorP
12 ) where
12 ) where
13
13
14+import Data.Type.Bool (type (||), type (&&))
14import GHC.Generics
15import GHC.Generics
15import GHC.TypeLits
16import GHC.TypeLits
16
17
17−import Data.Type.Bool (type (||), type (&&))
18−
19type family HasTotalFieldP (field :: Symbol) f :: Bool where
18type family HasTotalFieldP (field :: Symbol) f :: Bool where
20 HasTotalFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
19 HasTotalFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
21 = 'True
20 = 'True
src/Data/Generics/Product/Positions.hs+1−2
@@ -37,11 +37,10 @@ module Data.Generics.Product.Positions
37import Data.Generics.Internal.Lens
37import Data.Generics.Internal.Lens
38
38
39import Data.Kind
39import Data.Kind
40+import Data.Type.Bool
40import GHC.Generics
41import GHC.Generics
41import GHC.TypeLits
42import GHC.TypeLits
42
43
43−import Data.Type.Bool (type (&&), If, Not)
44−
45-- $example
44-- $example
46-- @
45-- @
47-- module Example where
46-- module Example where