@@ -28,7 +28,7 @@
2828module Data.Generics.Product.Fields
2929 ( -- *Lenses
3030
31− -- $setup
31+ -- $setup
3232 HasField (..)
3333 , HasField'
3434
@@ -46,6 +46,8 @@ import GHC.Generics
4646import GHC.TypeLits (Symbol, ErrorMessage(..), TypeError)
4747
4848-- $setup
49+-- == /Running example:/
50+--
4951-- >>> :set -XTypeApplications
5052-- >>> :set -XDataKinds
5153-- >>> :set -XDeriveGeneric
@@ -55,12 +57,18 @@ import GHC.TypeLits (Symbol, ErrorMessage(..), TypeError)
5557-- >>> :m +Data.Generics.Internal.Lens
5658-- >>> :m +Data.Function
5759-- >>> :{
58−-- data Human a = Human
59−-- { name :: String
60−-- , age :: Int
61−-- , address :: String
62−-- , other :: a
63−-- }
60+-- data Human a
61+-- = Human
62+-- { name :: String
63+-- , age :: Int
64+-- , address :: String
65+-- , other :: a
66+-- }
67+-- | HumanNoAddress
68+-- { name :: String
69+-- , age :: Int
70+-- , other :: a
71+-- }
6472-- deriving (Generic, Show)
6573-- human :: Human Bool
6674-- human = Human { name = "Tunyasz", age = 50, address = "London", other = False }
@@ -74,13 +82,31 @@ class HasField (field :: Symbol) s t a b | s field -> a, s field b -> t where
7482 -- >>> human ^. field @"age"
7583 -- 50
7684 --
77− -- If the field's type comes from a type parameter, it can be changed:
85+ -- === /Type changing/
86+ --
7887 -- >>> :t human
7988 -- human :: Human Bool
89+ --
8090 -- >>> :t human & field @"other" .~ (42 :: Int)
8191 -- human & field @"other" .~ (42 :: Int) :: Human Int
92+ --
8293 -- >>> human & field @"other" .~ 42
8394 -- Human {name = "Tunyasz", age = 50, address = "London", other = 42}
95+ --
96+ -- === /Type errors/
97+ --
98+ -- >>> human & field @"weight" .~ 42
99+ -- ...
100+ -- ... The type Human Bool does not contain a field named 'weight'.
101+ -- ...
102+ --
103+ -- >>> human & field @"address" .~ ""
104+ -- ...
105+ -- ... Not all constructors of the type Human Bool
106+ -- ... contain a field named 'address'.
107+ -- ... The offending constructors are:
108+ -- ... HumanNoAddress
109+ -- ...
84110 field :: Lens s t a b
85111
86112type HasField' field s a = HasField field s s a a
@@ -99,7 +125,7 @@ setField = set (field @f)
99125
100126instance -- see Note [Changing type parameters]
101127 ( Generic s
102− , ErrorUnless field s (HasTotalFieldP field (Rep s))
128+ , ErrorUnless field s (CollectField field (Rep s))
103129 , Generic t
104130 , s' ~ Proxied s
105131 , Generic s'
@@ -118,14 +144,24 @@ instance {-# OVERLAPPING #-} HasField f (Void2 t a) t a b where
118144instance {-# OVERLAPPING #-} HasField f (Void1 a) (Void1 b) a b where
119145 field = undefined
120146
121−type family ErrorUnless (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
122− ErrorUnless field s 'False
147+type family ErrorUnless (field :: Symbol) (s :: Type) (stat :: TypeStat) :: Constraint where
148+ ErrorUnless field s ('TypeStat _ _ '[])
123149 = TypeError
124150 ( 'Text "The type "
125151 ':<>: 'ShowType s
126− ':<>: 'Text " does not contain a field named "
127− ':<>: 'ShowType field
152+ ':<>: 'Text " does not contain a field named '"
153+ ':<>: 'Text field ':<>: 'Text "'."
154+ )
155+
156+ ErrorUnless field s ('TypeStat (n ': ns) _ _)
157+ = TypeError
158+ ( 'Text "Not all constructors of the type "
159+ ':<>: 'ShowType s
160+ ':$$: 'Text " contain a field named '"
161+ ':<>: 'Text field ':<>: 'Text "'."
162+ ':$$: 'Text "The offending constructors are:"
163+ ':$$: ShowConstuctors (n ': ns)
128164 )
129165
130− ErrorUnless _ _ 'True
166+ ErrorUnless _ _ ('TypeStat '[] '[] _)
131167 = ()