4Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
6Generically derive lenses and prisms for data types.
8Available on [Hackage](https://hackage.haskell.org/package/generic-lens)
10This package uses the GHC 8 `Generic` representation to derive various operations
11on data structures with lens interfaces, including structural subtype
12relationships between records and positional indexing into arbitrary product
15This is made possible by GHC 8's new Generics API, which provides metadata
16at the type-level (previously only value-level metadata was available).
18Examples 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).
25Record fields can be accessed by their label:
28data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
31sally = Person "Sally" 25
35>>> getField @"age" sally
38>>> setField @"age" 26 sally
39Person {name = "Sally", age = 26}
41>>> sally ^. field @"name"
44>>> sally & field @"name" .~ "Tamas"
45Person {name = "Tamas", age = 25}
47>>> sally ^. field @"pet"
49 • The type Person does not contain a field named "pet"
54Fields can be accessed by their position in the data structure (index starting at 1):
57data Point = Point Int Int Int deriving (Generic, Show)
58data Polygon = Polygon Point Point Point deriving (Generic, Show)
61polygon = Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 7 (-2))
65>>> getPosition @2 polygon
68>>> setPosition @1 (Point 26 5 3) polygon
69Polygon (Point 26 5 3) (Point 2 4 2) (Point 5 7 (-2))
71>>> polygon ^. position @1 . position @2
74>>> polygon & position @3 . position @2 %~ (+10)
75Polygon (Point 1 5 3) (Point 2 4 2) (Point 5 17 (-2))
77>>> polygon ^. position @10
79 • The type Polygon does not contain a field at position 10
82Since tuples are an instance of `Generic`, they also have positional lenses:
85>>> (("hello", True), 5) ^. position @1 . position @2
91Fields can be accessed by their type in the data structure, assuming that this
95data Person = Person { name :: String, age :: Int } deriving (Generic, Show)
96data Point = Point Int Int Int deriving (Generic, Show)
99sally = Person "Sally" 25
106>>> getTyped @String sally
109>>> setTyped @Int sally 26
110Person {name = "Sally", age = 26}
112>>> point ^. typed @Int
114 • The type Point contains multiple values of type Int; the choice of value is thus ambiguous
116>>> point & typed @String .~ "Point"
118 • The type Point does not contain a value of type [Char]
121### Structural subtyping
123A record is a (structural) `subtype' of another, if its fields are a superset of
131 } deriving (Generic, Show)
136 } deriving (Generic, Show)
139human = Human {name = "Tunyasz", age = 50, address = "London"}
144>>> upcast human :: Animal
145Animal {name = "Tunyasz", age = 50}
147-- 'smash' plug the smaller structure into the larger one
148>>> smash (Animal "dog" 10) human
149Human {name = "dog", age = 10, address = "London"}
151-- 'super' is a lens that focuses on a subrecord of a larger record:
152>>> human ^. super @Animal
153Animal {name = "Tunyasz", age = 50}
156We can apply a function that operates on a supertype to the larger (subtype)
157structure, by focusing on the supertype first:
160growUp :: Animal -> Animal
161growUp (Animal name age) = Animal name (age + 50)
163>>> human & super @Animal %~ growUp
164Human {name = "Tunyasz", age = 60, address = "London"}
169### Named constructors
171Constructor components can be accessed using the constructor's name:
177data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
178data Animal = Dog Dog | Cat Name Age | Duck Age deriving (Generic, Show)
180shep = Dog (MkDog "Shep" 4)
186>>> shep ^? _Ctor @"Dog"
187Just (MkDog {name = "Shep", age = 4})
189>>> shep ^? _Ctor @"Cat"
192>>> mog ^? _Ctor @"Cat"
195>>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
198>>> donald ^? _Ctor @"Giraffe"
200 • The type Animal does not contain a constructor named "Giraffe"
203### Typed constructors
205Constructor components can be accessed using the component's type, assuming
206that this type is unique:
212data Dog = MkDog { name :: Name, age :: Age } deriving (Generic, Show)
213data Animal = Dog Dog | Cat (Name, Age) | Duck Age deriving (Generic, Show)
215shep = Dog (MkDog "Shep" 4)
221>>> mog ^? _Typed @Dog
224>>> shep ^? _Typed @Dog
225Just (MkDog {name = "Shep", age = 4})
227>>> donald ^? _Typed @Age
230>>> donald ^? _Typed @Float
232 • The type Animal does not contain a constructor whose field is of type Float
234>>> _Typed @Age # 6 :: Animal
240+ [Toby Shaw](https://github.com/TobyShaw)
241+ [Will Jones](https://github.com/lunaris)
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list