on master help sign in
Type-changing lenses

Squashed commit of the following: commit 9cece814c5ce2c11333c43d33a37bf6ecac0790c Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Mon Nov 27 01:05:03 2017 +0000 Update README commit aeb63b2cd34830c9cd79ade8904ad78fbba8f757 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Sun Nov 26 18:57:38 2017 +0000 Use doctest commit 0c7742fefd5cc82a4e70c90e70b4676932ee05fc Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 22:41:38 2017 +0000 Type-changing Any commit 2f8c7c5cba6c7fc8e604f3402a71f67b8fe292ed Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 21:56:27 2017 +0000 Type-changing positional lens commit 21310bbcaa33038d1985a78711d23c7522a06be8 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 20:56:22 2017 +0000 Make types easier to read commit ba74ce67380f51384b35f0d26349c1f2ece1e36b Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 16:31:56 2017 +0000 Fix inlining on 8.0.2 commit 0fd5b33639c4add2f804049937a300dd24fb2259 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 16:31:27 2017 +0000 Whitespace commit 92386ed5d3a40681b56ec7c3be22640861925ed7 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 22 14:07:54 2017 +0000 Use more robust approach for type-chaning lenses commit 542ce7f279347c765453e422c6650634c8b6f905 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 15 16:09:52 2017 +0000 Add test for type-changing lens commit 9425124f63b1c1f6a3217110f93e927df1cbd333 Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 15 16:03:28 2017 +0000 Replace old field lens with the type-changing one commit 8f8b7cf66845fa12ef1763bfb607fc366bb0e36d Author: Csongor Kiss <kiss.csongor.kiss@gmail.com> Date: Wed Nov 15 13:50:18 2017 +0000 Add type-changing lenses with proper type inference

commit4e50855745b10ff62ae809aa1ec560542907b7b9 authorCsongor Kiss <kiss.csongor.kiss@gmail.com> dateMon 27 Nov 2017, 01:09 (9 years ago) parent462f56c
22 files changed+567−338
README.md+18−2 examples/Examples.hs+16−1 generic-lens.cabal+12−1 src/Data/Generics/Internal/Families.hs+3−2 src/Data/Generics/Internal/Families/Changing.hs+58 src/Data/Generics/Internal/Lens.hs+34−11 src/Data/Generics/Internal/Void.hs+16 src/Data/Generics/Product/Any.hs+23−23 src/Data/Generics/Product/Fields.hs+76−52 src/Data/Generics/Product/Internal/Fields.hs+22−16 src/Data/Generics/Product/Internal/Positions.hs+16−12 src/Data/Generics/Product/Internal/Subtype.hs+2−2 src/Data/Generics/Product/Positions.hs+49−42 src/Data/Generics/Product/Subtype.hs+34−25 src/Data/Generics/Product/Typed.hs+22−18 src/Data/Generics/Sum/Any.hs+28−30 src/Data/Generics/Sum/Constructors.hs+33−31 src/Data/Generics/Sum/Subtype.hs+41−39 src/Data/Generics/Sum/Typed.hs+38−29 stack.yaml+1−1 test/Spec.hs+18−1 test/doctest.hs+7
README.md+18−2
@@ -1,7 +1,6 @@
11# generic-lens
22
3−[![Build
4−Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
3+[![Build Status](https://travis-ci.org/kcsongor/generic-lens.svg?branch=master)](https://travis-ci.org/kcsongor/generic-lens)
54[![Hackage](https://img.shields.io/hackage/v/generic-lens.svg)](https://hackage.haskell.org/package/generic-lens)
65
76Generically derive lenses and prisms for data types.
@@ -50,6 +49,23 @@ error:
5049 • The type Person does not contain a field named "pet"
5150```
5251
52+If the accessed field is a type parameter that appears uniquely in the type,
53+then its type can be changed:
54+
55+```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}
67+```
68+
5369### Positional fields
5470
5571Fields can be accessed by their position in the data structure (index starting at 1):
examples/Examples.hs+16−1
@@ -11,7 +11,7 @@ module Examples where
1111
1212import GHC.Generics
1313import Data.Generics.Product
14−--import Control.Lens
14+import Control.Lens
1515
1616data Animal = Animal
1717 { name :: String
@@ -41,3 +41,18 @@ data MyRecord = MyRecord { field1 :: Int, field2 :: String } deriving Generic
4141
4242--g :: Subtype s MyRecord => s -> String
4343--g s = s ^. super @MyRecord . label @"field2"
44+
45+data Test a b = Test { fieldInt :: Int, fieldA :: a, fieldB :: b } deriving (Generic, Show)
46+
47+-- changedA :: Test Int String
48+-- >>> changedA
49+-- Test {fieldInt = 10, fieldA = 10, fieldB = "world"}
50+changedA = set (field @"fieldA") (10 :: Int) (Test 10 "hello" "world")
51+
52+-- changedB :: Test String Int
53+-- >>> changedB
54+-- Test {fieldInt = 10, fieldA = "hello", fieldB = 10}
55+changedB = set (field @"fieldB") (10 :: Int) (Test 10 "hello" "world")
56+
57+--changedInt = set (field @"fieldInt") ("hello") (Test 10 "hello" "world")
58+-- type error
generic-lens.cabal+12−1
@@ -1,5 +1,5 @@
11name: generic-lens
2−version: 0.4.1.1
2+version: 0.5.0.0
33synopsis: Generic data-structure operations exposed as lenses.
44description: 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.
55
@@ -34,9 +34,11 @@ library
3434 , Data.Generics.Internal.Lens
3535
3636 other-modules: Data.Generics.Internal.Families
37+ , Data.Generics.Internal.Families.Changing
3738 , Data.Generics.Internal.Families.Count
3839 , Data.Generics.Internal.Families.Has
3940 , Data.Generics.Internal.HList
41+ , Data.Generics.Internal.Void
4042
4143 , Data.Generics.Sum.Internal.Constructors
4244 , Data.Generics.Sum.Internal.Typed
@@ -53,6 +55,7 @@ library
5355
5456 build-depends: base >= 4.9 && <= 5.0
5557 , profunctors >= 5.0 && <= 6.0
58+ , tagged >= 0.8 && <= 0.9
5659
5760 hs-source-dirs: src
5861 default-language: Haskell2010
@@ -74,6 +77,14 @@ test-suite generic-lens-test
7477 default-language: Haskell2010
7578 ghc-options: -Wall
7679
80+test-suite doctests
81+ default-language: Haskell2010
82+ type: exitcode-stdio-1.0
83+ ghc-options: -threaded
84+ main-is: doctest.hs
85+ build-depends: base >4 && <5, doctest
86+ hs-source-dirs: test
87+
7788benchmark generic-lens-bench
7889 type: exitcode-stdio-1.0
7990 hs-source-dirs: benchmarks
src/Data/Generics/Internal/Families.hs+3−2
@@ -12,5 +12,6 @@ module Data.Generics.Internal.Families
1212 ( module Families
1313 ) where
1414
15−import Data.Generics.Internal.Families.Count as Families
16−import Data.Generics.Internal.Families.Has as Families
15+import Data.Generics.Internal.Families.Count as Families
16+import Data.Generics.Internal.Families.Has as Families
17+import Data.Generics.Internal.Families.Changing as Families
src/Data/Generics/Internal/Families/Changing.hsnew file+58
@@ -0,0 +1,58 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE PolyKinds #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE TypeOperators #-}
5+{-# LANGUAGE UndecidableInstances #-}
6+
7+module Data.Generics.Internal.Families.Changing where
8+
9+import GHC.TypeLits (Nat, type (+))
10+
11+{-
12+ Note [Changing type parameters]
13+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
14+
15+ To get good type inference for type-changing lenses, we want to be able
16+ map the field's type back to the type argument it corresponds to. This way,
17+ when the field is changed, we know what the result type of the structure is
18+ going to be.
19+
20+ However, for a given type @t@, its representation @Rep t@ forgets which types
21+ in the structure came from type variables, and which didn't. An @Int@ that
22+ results from the instantiation of the type paremeter and an @Int@ that was
23+ monomorphically specified in the structure are indistinguishable.
24+
25+ The solution is to replace the type arguments in the type with unique
26+ proxies, like: @T a b@ -> @T (P 1 a) (P 0 b)@. This way, if looking up
27+ a field's type yields something of shape @P _ _@, we know it came from a type
28+ parameter, and also know which.
29+
30+ If the field's type is a proxy, then its type is allowed to change, otherwise
31+ not. This also allows us to satisfy the functional dependency @s field b -> t@.
32+ If after doing the conversion on @s@, @field@'s type is @(P _ a), then @t@ is
33+ @s[b/a]@, otherwise @t ~ s@ and @b ~ a@.
34+-}
35+data P (i :: Nat) a
36+
37+type Proxied t = Proxied' t 0
38+
39+type family Proxied' (t :: k) (next :: Nat) :: k where
40+ Proxied' (t a :: k) next = (Proxied' t (next + 1)) (P next a)
41+ Proxied' t _ = t
42+
43+type family UnProxied (t :: k) :: k where
44+ UnProxied (t (P _ a) :: k) = UnProxied t a
45+ UnProxied t = t
46+
47+type family Change (t :: k) (target :: Nat) (to :: j) :: k where
48+ Change (t (P target _) :: k) target to = t (P target to)
49+ Change (t a :: k) target to = Change t target to a
50+ Change t _ _ = t
51+
52+type family IsParam a where
53+ IsParam (P _ _) = 'True
54+ IsParam _ = 'False
55+
56+type family IndexOf a where
57+ IndexOf (P i a) = i
58+
src/Data/Generics/Internal/Lens.hs+34−11
@@ -16,14 +16,20 @@
1616-----------------------------------------------------------------------------
1717module Data.Generics.Internal.Lens where
1818
19−import Control.Applicative (Const(..))
20−import Data.Functor.Identity (Identity(..))
21−import Data.Profunctor (Choice(right'), Profunctor(dimap))
22−import GHC.Generics ((:*:)(..), (:+:)(..), Generic(..), M1(..), Rep)
19+import Control.Applicative (Const(..))
20+import Data.Functor.Identity (Identity(..))
21+import Data.Monoid (First (..))
22+import Data.Profunctor (Choice(right'), Profunctor(dimap))
23+import Data.Profunctor.Unsafe ((#.), (.#))
24+import Data.Tagged
25+import GHC.Generics ((:*:)(..), (:+:)(..), Generic(..), M1(..), Rep)
2326
2427-- | Type alias for lens
2528type Lens' s a
26− = forall f. Functor f => (a -> f a) -> s -> f s
29+ = Lens s s a a
30+
31+type Lens s t a b
32+ = forall f. Functor f => (a -> f b) -> s -> f t
2733
2834-- | Type alias for prism
2935type Prism' s a
@@ -32,6 +38,9 @@ type Prism' s a
3238type Iso' s a
3339 = forall p f. (Profunctor p, Functor f) => p a (f a) -> p s (f s)
3440
41+type Iso s t a b
42+ = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)
43+
3544-- | Getting
3645(^.) :: s -> ((a -> Const a a) -> s -> Const a s) -> a
3746s ^. l = getConst (l Const s)
@@ -42,13 +51,26 @@ set :: ((a -> Identity b) -> s -> Identity t) -> b -> s -> t
4251set l b
4352 = runIdentity . l (\_ -> Identity b)
4453
54+infixr 4 .~
55+(.~) :: ((a -> Identity b) -> s -> Identity t) -> b -> s -> t
56+(.~) = set
57+
58+infixl 8 ^?
59+(^?) :: s -> ((a -> Const (First a) a) -> s -> Const (First a) s) -> Maybe a
60+s ^? l = getFirst (fmof l (First #. Just) s)
61+ where fmof l' f = getConst #. l' (Const #. f)
62+
63+infixr 8 #
64+(#) :: (Tagged b (Identity b) -> Tagged t (Identity t)) -> b -> t
65+(#) p = runIdentity #. unTagged #. p .# Tagged .# Identity
66+
4567-- | Lens focusing on the first element of a product
46−first :: Lens' ((a :*: b) x) (a x)
68+first :: Lens ((a :*: b) x) ((a' :*: b) x) (a x) (a' x)
4769first f (a :*: b)
4870 = fmap (:*: b) (f a)
4971
5072-- | Lens focusing on the second element of a product
51−second :: Lens' ((a :*: b) x) (b x)
73+second :: Lens ((a :*: b) x) ((a :*: b') x) (b x) (b' x)
5274second f (a :*: b)
5375 = fmap (a :*:) (f b)
5476
@@ -70,19 +92,20 @@ prism :: (a -> s) -> (s -> Either s a) -> Prism' s a
7092prism bt seta = dimap seta (either pure (fmap bt)) . right'
7193
7294-- | A type and its generic representation are isomorphic
73−repIso :: Generic a => Iso' a (Rep a x)
95+repIso :: (Generic a, Generic b) => Iso a b (Rep a x) (Rep b x)
7496repIso = dimap from (fmap to)
7597
7698-- | 'M1' is just a wrapper around `f p`
77−mIso :: Iso' (M1 i c f p) (f p)
99+--mIso :: Iso' (M1 i c f p) (f p)
100+mIso :: Iso (M1 i c f p) (M1 i c g p) (f p) (g p)
78101mIso = dimap unM1 (fmap M1)
79102
80103-- These are specialised versions of the Isos above. On GHC 8.0.2, having
81104-- these functions eta-expanded allows the optimiser to inline these functions.
82−mLens :: Lens' (M1 i c f p) (f p)
105+mLens :: Lens (M1 i c f p) (M1 i c g p) (f p) (g p)
83106mLens f s = mIso f s
84107
85−repLens :: Generic a => Lens' a (Rep a x)
108+repLens :: (Generic a, Generic b) => Lens a b (Rep a x) (Rep b x)
86109repLens f s = repIso f s
87110
88111sumIso :: Iso' ((a :+: b) x) (Either (a x) (b x))
src/Data/Generics/Internal/Void.hsnew file+16
@@ -0,0 +1,16 @@
1+module Data.Generics.Internal.Void where
2+
3+{-
4+ Note [Uncluttering type signatures]
5+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
6+
7+ Because the various instances in the library always match (the Has* classes
8+ are essentially glorified constraint synonyms), they get replaced with
9+ their constraints, resulting in large, unreadable types.
10+
11+ Writing an (overlapping instance) for this Void type means that the original
12+ instance might not be the one selected, thus GHC leaves the constraints in
13+ place until further information is provided, at which point the type
14+ machinery has sufficient information to reduce to sensible types.
15+-}
16+data Void
src/Data/Generics/Product/Any.hs+23−23
@@ -6,6 +6,7 @@
66{-# LANGUAGE PolyKinds #-}
77{-# LANGUAGE ScopedTypeVariables #-}
88{-# LANGUAGE TypeApplications #-}
9+{-# LANGUAGE TypeFamilies #-}
910{-# LANGUAGE UndecidableInstances #-}
1011
1112-----------------------------------------------------------------------------
@@ -24,7 +25,7 @@
2425module Data.Generics.Product.Any
2526 ( -- *Lenses
2627 --
27− -- $example
28+ -- $setup
2829 HasAny (..)
2930 ) where
3031
@@ -33,26 +34,25 @@ import Data.Generics.Product.Fields
3334import Data.Generics.Product.Positions
3435import Data.Generics.Product.Typed
3536
36−-- $example
37−-- @
38−-- module Example where
39−--
40−-- import Data.Generics.Product
41−-- import GHC.Generics
42−--
43−-- data Human = Human
44−-- { name :: String
45−-- , age :: Int
46−-- , address :: String
47−-- }
48−-- deriving (Generic, Show)
49−--
50−-- human :: Human
51−-- human = Human \"Tunyasz\" 50 \"London\"
52−-- @
37+-- $setup
38+-- >>> :set -XTypeApplications
39+-- >>> :set -XDataKinds
40+-- >>> :set -XDeriveGeneric
41+-- >>> import GHC.Generics
42+-- >>> :m +Data.Generics.Internal.Lens
43+-- >>> :{
44+-- data Human = Human
45+-- { name :: String
46+-- , age :: Int
47+-- , address :: String
48+-- }
49+-- deriving (Generic, Show)
50+-- human :: Human
51+-- human = Human "Tunyasz" 50 "London"
52+-- :}
5353
5454-- |Records that have generic lenses.
55−class HasAny (sel :: k) a s | s sel k -> a where
55+class HasAny (sel :: k) s t a b | s sel k -> a, s sel k b -> t where
5656 -- |A lens that focuses on a part of a product as identified by some
5757 -- selector. Currently supported selectors are field names, positions and
5858 -- unique types. Compatible with the lens package's 'Control.Lens.Lens'
@@ -64,13 +64,13 @@ class HasAny (sel :: k) a s | s sel k -> a where
6464 -- "Tunyasz"
6565 -- >>> human ^. the @3
6666 -- "London"
67− the :: Lens' s a
67+ the :: Lens s t a b
6868
69−instance HasPosition i a s => HasAny i a s where
69+instance HasPosition i s t a b => HasAny i s t a b where
7070 the = position @i
7171
72−instance HasField field a s => HasAny field a s where
72+instance HasField field s t a b => HasAny field s t a b where
7373 the = field @field
7474
75−instance HasType a s => HasAny a a s where
75+instance (HasType a s, t ~ s, a ~ b) => HasAny a s t a b where
7676 the = typed @a
src/Data/Generics/Product/Fields.hs+76−52
@@ -1,14 +1,16 @@
1−{-# LANGUAGE AllowAmbiguousTypes #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE KindSignatures #-}
6−{-# LANGUAGE MultiParamTypeClasses #-}
7−{-# LANGUAGE ScopedTypeVariables #-}
8−{-# LANGUAGE TypeApplications #-}
9−{-# LANGUAGE TypeFamilies #-}
10−{-# LANGUAGE TypeOperators #-}
11−{-# LANGUAGE UndecidableInstances #-}
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
3+{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE ScopedTypeVariables #-}
8+{-# LANGUAGE TypeApplications #-}
9+{-# LANGUAGE TypeFamilies #-}
10+{-# LANGUAGE TypeInType #-}
11+{-# LANGUAGE TypeOperators #-}
12+{-# LANGUAGE UndecidableInstances #-}
13+{-# LANGUAGE UndecidableSuperClasses #-}
1214
1315-----------------------------------------------------------------------------
1416-- |
@@ -26,72 +28,94 @@
2628module Data.Generics.Product.Fields
2729 ( -- *Lenses
2830
29− -- $example
31+ -- $setup
3032 HasField (..)
33+ , HasField'
34+
35+ , getField
36+ , setField
3137 ) where
3238
3339import Data.Generics.Internal.Families
3440import Data.Generics.Internal.Lens
41+import Data.Generics.Internal.Void
3542import Data.Generics.Product.Internal.Fields
3643
3744import Data.Kind (Constraint, Type)
3845import GHC.Generics
3946import GHC.TypeLits (Symbol, ErrorMessage(..), TypeError)
47+import Data.Type.Bool (If)
4048
41−-- $example
42−-- @
43−-- module Example where
44−--
45−-- import Data.Generics.Product
46−-- import GHC.Generics
47−--
48−-- data Human = Human
49−-- { name :: String
50−-- , age :: Int
51−-- , address :: String
52−-- }
53−-- deriving (Generic, Show)
54−--
55−-- human :: Human
56−-- human = Human \"Tunyasz\" 50 \"London\"
57−-- @
49+-- $setup
50+-- >>> :set -XTypeApplications
51+-- >>> :set -XDataKinds
52+-- >>> :set -XDeriveGeneric
53+-- >>> :set -XGADTs
54+-- >>> :set -XFlexibleContexts
55+-- >>> import GHC.Generics
56+-- >>> :m +Data.Generics.Internal.Lens
57+-- >>> :m +Data.Function
58+-- >>> :{
59+-- data Human a = Human
60+-- { name :: String
61+-- , age :: Int
62+-- , address :: String
63+-- , other :: a
64+-- }
65+-- deriving (Generic, Show)
66+-- human :: Human Bool
67+-- human = Human { name = "Tunyasz", age = 50, address = "London", other = False }
68+-- :}
5869
5970-- |Records that have a field with a given name.
60−class HasField (field :: Symbol) a s | s field -> a where
71+class HasField (field :: Symbol) s t a b | s field b -> t, s field -> a where
6172 -- |A lens that focuses on a field with a given name. Compatible with the
6273 -- lens package's 'Control.Lens.Lens' type.
6374 --
6475 -- >>> human ^. field @"age"
6576 -- 50
66− -- >>> human & field @"name" .~ "Tamas"
67− -- Human {name = "Tamas", age = 50, address = "London"}
68− field :: Lens' s a
69− field f s
70− = fmap (flip (setField @field) s) (f (getField @field s))
71−
72− -- |Get 'field'
7377 --
74− -- >>> getField @"name" human
75− -- "Tunyasz"
76− getField :: s -> a
77− getField s = s ^. field @field
78+ -- If the field's type comes from a type parameter, it can be changed:
79+ -- >>> :t human
80+ -- human :: Human Bool
81+ -- >>> :t human & field @"other" .~ 42
82+ -- human & field @"other" .~ 42 :: Num b => Human b
83+ -- >>> human & field @"other" .~ 42
84+ -- Human {name = "Tunyasz", age = 50, address = "London", other = 42}
85+ field :: Lens s t a b
7886
79− -- |Set 'field'
80− --
81− -- >>> setField @"age" (setField @"name" "Tamas" human) 30
82− -- Human {name = "Tamas", age = 30, address = "London"}
83− setField :: a -> s -> s
84− setField = set (field @field)
87+type HasField' field s a = HasField field s s a a
8588
86− {-# MINIMAL field | setField, getField #-}
89+-- |
90+-- >>> getField @"age" human
91+-- 50
92+getField :: forall f s a. HasField' f s a => s -> a
93+getField s = s ^. field @f
8794
88−instance
95+-- |
96+-- >>> setField @"age" 60 human
97+-- Human {name = "Tunyasz", age = 60, address = "London", other = False}
98+setField :: forall f s a. HasField' f s a => a -> s -> s
99+setField = set (field @f)
100+
101+instance -- see Note [Changing type parameters]
89102 ( Generic s
90103 , ErrorUnless field s (HasTotalFieldP field (Rep s))
91− , GHasField field (Rep s) a
92− ) => HasField field a s where
104+ , Generic t
105+ , s' ~ Proxied s
106+ , Generic s'
107+ , GHasField' field (Rep s) a
108+ , GHasField' field (Rep s') a'
109+ , GHasField field (Rep s) (Rep t) a b
110+ , '(t', b') ~ If (IsParam a') '(Change s' (IndexOf a') b, P (IndexOf a') b) '(s', b)
111+ , t ~ UnProxied t'
112+ ) => HasField field s t a b where
113+
114+ field f s = ravel (repLens . gfield @field) f s
93115
94− field = ravel (repLens . gfield @field)
116+-- See Note [Uncluttering type signatures]
117+instance {-# OVERLAPPING #-} HasField f Void Void Void Void where
118+ field = undefined
95119
96120type family ErrorUnless (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
97121 ErrorUnless field s 'False
src/Data/Generics/Product/Internal/Fields.hs+22−16
@@ -1,9 +1,11 @@
11{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
23{-# LANGUAGE DataKinds #-}
34{-# LANGUAGE FlexibleInstances #-}
45{-# LANGUAGE FunctionalDependencies #-}
56{-# LANGUAGE KindSignatures #-}
67{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE Rank2Types #-}
79{-# LANGUAGE ScopedTypeVariables #-}
810{-# LANGUAGE TypeApplications #-}
911{-# LANGUAGE TypeFamilies #-}
@@ -25,6 +27,7 @@
2527
2628module Data.Generics.Product.Internal.Fields
2729 ( GHasField (..)
30+ , GHasField'
2831 ) where
2932
3033import Data.Generics.Internal.Families
@@ -36,36 +39,39 @@ import GHC.TypeLits (Symbol)
3639
3740-- |As 'HasField' but over generic representations as defined by
3841-- "GHC.Generics".
39−class GHasField (field :: Symbol) (f :: Type -> Type) a | field f -> a where
40− gfield :: Lens' (f x) a
42+class GHasField (field :: Symbol) (s :: Type -> Type) (t :: Type -> Type) a b | s field -> a, t field -> b where
43+ gfield :: Lens (s x) (t x) a b
4144
42−instance GProductHasField field l r a (HasTotalFieldP field l)
43− => GHasField field (l :*: r) a where
45+type GHasField' field s a = GHasField field s s a a
4446
45− gfield = gproductField @field @_ @_ @_ @(HasTotalFieldP field l)
47+instance GProductHasField field l r l' r' a b (HasTotalFieldP field l)
48+ => GHasField field (l :*: r) (l' :*: r') a b where
4649
47−instance (GHasField field l a, GHasField field r a)
48− => GHasField field (l :+: r) a where
50+ gfield = gproductField @field @_ @_ @_ @_ @_ @_ @(HasTotalFieldP field l)
4951
50− gfield = combine (gfield @field @l) (gfield @field @r)
52+instance (GHasField field r r a a, GHasField field l l a a, GHasField field l l' a b, GHasField field r r' a b)
53+ => GHasField field (l :+: r) (l' :+: r') a b where
5154
52−instance GHasField field (K1 R a) a where
55+ gfield f (L1 s) = fmap (\a -> L1 (set (gfield @field) a s)) (f (s ^. gfield @field))
56+ gfield f (R1 t) = fmap (\a -> R1 (set (gfield @field) a t)) (f (t ^. gfield @field))
57+
58+instance GHasField field (K1 R a) (K1 R b) a b where
5359 gfield f (K1 x) = fmap K1 (f x)
5460
55−instance GHasField field (S1 ('MetaSel ('Just field) upkd str infstr) (Rec0 a)) a where
61+instance GHasField field (S1 ('MetaSel ('Just field) upkd str infstr) (Rec0 a)) (S1 ('MetaSel ('Just field) upkd str infstr) (Rec0 b)) a b where
5662 gfield = mLens . gfield @field
5763
58−instance GHasField field f a => GHasField field (M1 D meta f) a where
64+instance (Functor g, GHasField field f g a b) => GHasField field (M1 D meta f) (M1 D meta g) a b where
5965 gfield = mLens . gfield @field
6066
61−instance GHasField field f a => GHasField field (M1 C meta f) a where
67+instance GHasField field f g a b => GHasField field (M1 C meta f) (M1 C meta g) a b where
6268 gfield = mLens . gfield @field
6369
64−class GProductHasField (field :: Symbol) l r a (left :: Bool) | left field l r -> a where
65− gproductField :: Lens' ((l :*: r) x) a
70+class GProductHasField (field :: Symbol) l r l' r' a b (left :: Bool) | field l r -> a, field l' r' -> b where
71+ gproductField :: Lens ((l :*: r) x) ((l' :*: r') x) a b
6672
67−instance GHasField field l a => GProductHasField field l r a 'True where
73+instance GHasField field l l' a b => GProductHasField field l r l' r a b 'True where
6874 gproductField = first . gfield @field
6975
70−instance GHasField field r a => GProductHasField field l r a 'False where
76+instance GHasField field r r' a b => GProductHasField field l r l r' a b 'False where
7177 gproductField = second . gfield @field
src/Data/Generics/Product/Internal/Positions.hs+16−12
@@ -1,5 +1,7 @@
11{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
23{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
35{-# LANGUAGE FlexibleInstances #-}
46{-# LANGUAGE FunctionalDependencies #-}
57{-# LANGUAGE KindSignatures #-}
@@ -26,6 +28,7 @@
2628
2729module Data.Generics.Product.Internal.Positions
2830 ( GHasPosition (..)
31+ , GHasPosition'
2932 , type (<?)
3033 , Size
3134 ) where
@@ -39,31 +42,32 @@ import GHC.TypeLits (type (<=?), type (+), Nat)
3942
4043-- |As 'HasPosition' but over generic representations as defined by
4144-- "GHC.Generics".
42−class GHasPosition (offset :: Nat) (i :: Nat) (f :: Type -> Type) a | offset i f -> a where
43− gposition :: Lens' (f x) a
45+class GHasPosition (offset :: Nat) (i :: Nat) (s :: Type -> Type) (t :: Type -> Type) a b | s offset i -> a, s t offset i -> b where
46+ gposition :: Lens (s x) (t x) a b
4447
45−instance GHasPosition i i (K1 R a) a where
48+type GHasPosition' i s a = GHasPosition 1 i s s a a
49+
50+instance GHasPosition i i (K1 R a) (K1 R b) a b where
4651 gposition f (K1 x) = fmap K1 (f x)
4752
48−instance GHasPosition offset i f a => GHasPosition offset i (M1 m meta f) a where
53+instance GHasPosition offset i s t a b => GHasPosition offset i (M1 m meta s) (M1 m meta t) a b where
4954 gposition = mLens . gposition @offset @i
5055
5156instance
5257 ( goLeft ~ (i <? (offset + Size l))
5358 , offset' ~ (If goLeft offset (offset + Size l))
54− , GProductHasPosition offset' i l r a goLeft
55− ) => GHasPosition offset i (l :*: r) a where
56−
57− gposition = gproductPosition @offset' @i @_ @_ @_ @goLeft
59+ , GProductHasPosition offset' i l r l' r' a b goLeft
60+ ) => GHasPosition offset i (l :*: r) (l' :*: r') a b where
5861
62+ gposition = gproductPosition @offset' @i @_ @_ @_ @_ @_ @_ @goLeft
5963
60−class GProductHasPosition (offset :: Nat) (i :: Nat) l r a (left :: Bool) | offset i l r left -> a where
61− gproductPosition :: Lens' ((l :*: r) x) a
64+class GProductHasPosition (offset :: Nat) (i :: Nat) l r l' r' a b (left :: Bool) | offset i l r -> a, offset i l r l' r' -> b where
65+ gproductPosition :: Lens ((l :*: r) x) ((l' :*: r') x) a b
6266
63−instance GHasPosition offset i l a => GProductHasPosition offset i l r a 'True where
67+instance GHasPosition offset i l l' a b => GProductHasPosition offset i l r l' r a b 'True where
6468 gproductPosition = first . gposition @offset @i
6569
66−instance GHasPosition offset i r a => GProductHasPosition offset i l r a 'False where
70+instance GHasPosition offset i r r' a b => GProductHasPosition offset i l r l r' a b 'False where
6771 gproductPosition = second . gposition @offset @i
6872
6973type family Size f :: Nat where
src/Data/Generics/Product/Internal/Subtype.hs+2−2
@@ -47,7 +47,7 @@ instance (GUpcast sub a, GUpcast sub b) => GUpcast sub (a :*: b) where
4747 gupcast rep = gupcast rep :*: gupcast rep
4848
4949instance
50− GHasField field sub t
50+ GHasField field sub sub t t
5151 => GUpcast sub (S1 ('MetaSel ('Just field) p f b) (Rec0 t)) where
5252
5353 gupcast r = M1 (K1 (r ^. gfield @field))
@@ -84,7 +84,7 @@ class GSmashLeaf sub sup (w :: Bool) where
8484 gsmashLeaf :: sup p -> sub p -> sub p
8585
8686instance
87− GHasField field sup t
87+ GHasField field sup sup t t
8888 => GSmashLeaf (S1 ('MetaSel ('Just field) p f b) (Rec0 t)) sup 'True where
8989 gsmashLeaf sup _ = M1 (K1 (sup ^. gfield @field))
9090
src/Data/Generics/Product/Positions.hs+49−42
@@ -1,5 +1,7 @@
11{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE ConstraintKinds #-}
23{-# LANGUAGE DataKinds #-}
4+{-# LANGUAGE FlexibleContexts #-}
35{-# LANGUAGE FlexibleInstances #-}
46{-# LANGUAGE FunctionalDependencies #-}
57{-# LANGUAGE KindSignatures #-}
@@ -27,73 +29,78 @@
2729module Data.Generics.Product.Positions
2830 ( -- *Lenses
2931
30− -- $example
32+ -- $setup
3133 HasPosition (..)
34+ , HasPosition'
35+
36+ , getPosition
37+ , setPosition
3238 ) where
3339
3440import Data.Generics.Internal.Lens
41+import Data.Generics.Internal.Void
42+import Data.Generics.Internal.Families
3543import Data.Generics.Product.Internal.Positions
3644
3745import Data.Kind (Constraint, Type)
38−import Data.Type.Bool (type (&&))
46+import Data.Type.Bool (type (&&), If)
3947import GHC.Generics
4048import GHC.TypeLits (type (<=?), Nat, TypeError, ErrorMessage(..))
4149
42−-- $example
43−-- @
44−-- module Example where
45−--
46−-- import Data.Generics.Product
47−-- import GHC.Generics
48−--
49−-- data Human = Human
50−-- { name :: String
51−-- , age :: Int
52−-- , address :: String
53−-- }
54−-- deriving (Generic, Show)
55−--
56−-- human :: Human
57−-- human = Human \"Tunyasz\" 50 \"London\"
58−-- @
50+-- $setup
51+-- >>> :set -XTypeApplications
52+-- >>> :set -XDataKinds
53+-- >>> :set -XDeriveGeneric
54+-- >>> import GHC.Generics
55+-- >>> :m +Data.Generics.Internal.Lens
56+-- >>> :m +Data.Function
57+-- >>> :{
58+-- data Human = Human
59+-- { name :: String
60+-- , age :: Int
61+-- , address :: String
62+-- }
63+-- deriving (Generic, Show)
64+-- human :: Human
65+-- human = Human "Tunyasz" 50 "London"
66+-- :}
5967
6068-- |Records that have a field at a given position.
61−class HasPosition (i :: Nat) a s | s i -> a where
69+class HasPosition (i :: Nat) s t a b | s i -> a, s i b -> t where
6270 -- |A lens that focuses on a field at a given position. Compatible with the
6371 -- lens package's 'Control.Lens.Lens' type.
6472 --
6573 -- >>> human ^. position @1
6674 -- "Tunyasz"
67− -- >>> human & position @2 .~ "Berlin"
75+ -- >>> human & position @3 .~ "Berlin"
6876 -- Human {name = "Tunyasz", age = 50, address = "Berlin"}
69− position :: Lens' s a
70− position f s
71− = fmap (flip (setPosition @i) s) (f (getPosition @i s))
72− -- = fmap (setPosition s) (f (getPosition s))
77+ position :: Lens s t a b
7378
74− -- |Get positional field
75− --
76− -- >>> getPosition @1 human
77− -- "Tunyasz"
78− getPosition :: s -> a
79− getPosition s = s ^. position @i
79+type HasPosition' i s a = HasPosition i s s a a
8080
81− -- |Set positional field
82− --
83− -- >>> setPosition @2 (setField @1 "Tamas" human) 30
84− -- Human "Tamas" 30 "London"
85− setPosition :: a -> s -> s
86− setPosition = set (position @i)
81+getPosition :: forall i s a. HasPosition' i s a => s -> a
82+getPosition s = s ^. position @i
8783
88− {-# MINIMAL position | setPosition, getPosition #-}
84+setPosition :: forall i s a. HasPosition' i s a => a -> s -> s
85+setPosition = set (position @i)
8986
90−instance
87+instance -- see Note [Changing type parameters]
9188 ( Generic s
9289 , ErrorUnless i s (0 <? i && i <=? Size (Rep s))
93− , GHasPosition 1 i (Rep s) a
94− ) => HasPosition i a s where
90+ , Generic t
91+ , s' ~ Proxied s
92+ , GHasPosition' i (Rep s) a
93+ , GHasPosition' i (Rep s') a'
94+ , GHasPosition 1 i (Rep s) (Rep t) a b
95+ , '(t', b') ~ If (IsParam a') '(Change s' (IndexOf a') b, P (IndexOf a') b) '(s', b)
96+ , t ~ UnProxied t'
97+ ) => HasPosition i s t a b where
98+
99+ position f s = ravel (repLens . gposition @1 @i) f s
95100
96− position = ravel (repLens . gposition @1 @i)
101+-- See Note [Uncluttering type signatures]
102+instance {-# OVERLAPPING #-} HasPosition f Void Void Void Void where
103+ position = undefined
97104
98105type family ErrorUnless (i :: Nat) (s :: Type) (hasP :: Bool) :: Constraint where
99106 ErrorUnless i s 'False
src/Data/Generics/Product/Subtype.hs+34−25
@@ -28,36 +28,38 @@
2828module Data.Generics.Product.Subtype
2929 ( -- *Lenses
3030 --
31− -- $example
31+ -- $setup
3232 Subtype (..)
3333 ) where
3434
3535import Data.Generics.Internal.Lens
36+import Data.Generics.Internal.Void
3637import Data.Generics.Product.Internal.Subtype
3738
3839import GHC.Generics (Generic (Rep, to, from) )
3940
40−-- $example
41−-- @
42−-- module Example where
43−--
44−-- import Data.Generics.Product
45−-- import GHC.Generics
46−--
47−-- data Human = Human
48−-- { name :: String
49−-- , age :: Int
50−-- , address :: String
51−-- } deriving (Generic, Show)
52−--
53−-- data Animal = Animal
54−-- { name :: String
55−-- , age :: Int
56−-- } deriving (Generic, Show)
57−--
58−-- human :: Human
59−-- human = Human \"Tunyasz\" 50 \"London\"
60−-- @
41+-- $setup
42+-- >>> :set -XTypeApplications
43+-- >>> :set -XDataKinds
44+-- >>> :set -XDeriveGeneric
45+-- >>> :set -XDuplicateRecordFields
46+-- >>> import GHC.Generics
47+-- >>> :m +Data.Generics.Internal.Lens
48+-- >>> :{
49+-- data Human = Human
50+-- { name :: String
51+-- , age :: Int
52+-- , address :: String
53+-- }
54+-- deriving (Generic, Show)
55+-- data Animal = Animal
56+-- { name :: String
57+-- , age :: Int
58+-- }
59+-- deriving (Generic, Show)
60+-- human :: Human
61+-- human = Human "Tunyasz" 50 "London"
62+-- :}
6163
6264-- |Structural subtype relationship
6365--
@@ -94,11 +96,18 @@ class Subtype sup sub where
9496
9597 {-# MINIMAL super | smash, upcast #-}
9698
99+-- TODO: improve type error by showing a diff of fields
97100instance
98− ( GSmash (Rep a) (Rep b)
99− , GUpcast (Rep a) (Rep b)
100− , Generic a
101+ ( Generic a
101102 , Generic b
103+ , GSmash (Rep a) (Rep b)
104+ , GUpcast (Rep a) (Rep b)
102105 ) => Subtype b a where
103106 smash p b = to $ gsmash (from p) (from b)
104107 upcast = to . gupcast . from
108+
109+-- See Note [Uncluttering type signatures]
110+instance {-# OVERLAPPING #-} Subtype a Void where
111+ super = undefined
112+instance {-# OVERLAPPING #-} Subtype Void a where
113+ super = undefined
src/Data/Generics/Product/Typed.hs+22−18
@@ -26,35 +26,35 @@
2626module Data.Generics.Product.Typed
2727 ( -- *Lenses
2828 --
29− -- $example
29+ -- $setup
3030 HasType (..)
3131 ) where
3232
3333import Data.Generics.Internal.Families
3434import Data.Generics.Internal.Lens
35+import Data.Generics.Internal.Void
3536import Data.Generics.Product.Internal.Typed
3637
3738import Data.Kind (Constraint, Type)
3839import GHC.Generics (Generic (Rep))
3940import GHC.TypeLits (TypeError, ErrorMessage (..))
4041
41−-- $example
42−-- @
43−-- module Example where
44−--
45−-- import Data.Generics.Product
46−-- import GHC.Generics
47−--
48−-- data Human = Human
49−-- { name :: String
50−-- , age :: Int
51−-- , address :: String
52−-- }
53−-- deriving (Generic, Show)
54−--
55−-- human :: Human
56−-- human = Human \"Tunyasz\" 50 \"London\"
57−-- @
42+-- $setup
43+-- >>> :set -XTypeApplications
44+-- >>> :set -XDataKinds
45+-- >>> :set -XDeriveGeneric
46+-- >>> import GHC.Generics
47+-- >>> :m +Data.Generics.Internal.Lens
48+-- >>> :{
49+-- data Human = Human
50+-- { name :: String
51+-- , age :: Int
52+-- , address :: String
53+-- }
54+-- deriving (Generic, Show)
55+-- human :: Human
56+-- human = Human "Tunyasz" 50 "London"
57+-- :}
5858
5959-- |Records that have a field with a unique type.
6060class HasType a s where
@@ -85,6 +85,10 @@ instance
8585
8686 typed = ravel (repLens . gtyped)
8787
88+-- See Note [Uncluttering type signatures]
89+instance {-# OVERLAPPING #-} HasType a Void where
90+ typed = undefined
91+
8892type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constraint where
8993 ErrorUnlessOne a s 'None
9094 = TypeError
src/Data/Generics/Sum/Any.hs+28−30
@@ -24,7 +24,7 @@
2424module Data.Generics.Sum.Any
2525 ( -- *Prisms
2626 --
27− -- $example
27+ -- $setup
2828 AsAny (..)
2929 ) where
3030
@@ -32,34 +32,31 @@ import Data.Generics.Internal.Lens
3232import Data.Generics.Sum.Constructors
3333import Data.Generics.Sum.Typed
3434
35−-- $example
36−-- @
37−-- module Example where
38−--
39−-- import Data.Generics.Sum
40−-- import GHC.Generics
41−--
42−-- data Animal
43−-- = Dog Dog
44−-- | Cat Name Age
45−-- | Duck Age
46−-- deriving (Generic, Show)
47−--
48−-- data Dog = MkDog
49−-- { name :: Name
50−-- , age :: Age
51−-- }
52−-- deriving (Generic, Show)
53−--
54−-- type Name = String
55−-- type Age = Int
56−--
57−-- dog, cat, duck :: Animal
58−--
59−-- dog = Dog (MkDog "Shep" 3)
60−-- cat = Cat "Mog" 5
61−-- duck = Duck 2
62−-- @
35+-- $setup
36+-- >>> :set -XTypeApplications
37+-- >>> :set -XDataKinds
38+-- >>> :set -XDeriveGeneric
39+-- >>> import GHC.Generics
40+-- >>> :m +Data.Generics.Internal.Lens
41+-- >>> :{
42+-- data Animal
43+-- = Dog Dog
44+-- | Cat Name Age
45+-- | Duck Age
46+-- deriving (Generic, Show)
47+-- data Dog
48+-- = MkDog
49+-- { name :: Name
50+-- , age :: Age
51+-- }
52+-- deriving (Generic, Show)
53+-- type Name = String
54+-- type Age = Int
55+-- dog, cat, duck :: Animal
56+-- dog = Dog (MkDog "Shep" 3)
57+-- cat = Cat "Mog" 5
58+-- duck = Duck 2
59+-- :}
6360
6461-- |Sums that have generic prisms.
6562class AsAny (sel :: k) a s | s sel k -> a where
@@ -78,7 +75,7 @@ class AsAny (sel :: k) a s | s sel k -> a where
7875 -- >>> cat ^? _As @"Cat"
7976 -- Just ("Mog",5)
8077 -- >>> _As @"Cat" # ("Garfield", 6) :: Animal
81− -- Cat ("Garfield",6)
78+ -- Cat "Garfield" 6
8279 -- >>> duck ^? _As @Age
8380 -- Just 2
8481 _As :: Prism' s a
@@ -88,3 +85,4 @@ instance AsConstructor ctor a s => AsAny ctor a s where
8885
8986instance AsType a s => AsAny a a s where
9087 _As = _Typed @a
88+
src/Data/Generics/Sum/Constructors.hs+33−31
@@ -26,46 +26,44 @@
2626module Data.Generics.Sum.Constructors
2727 ( -- *Prisms
2828
29− -- $example
29+ -- $setup
3030 AsConstructor (..)
3131 ) where
3232
3333import Data.Generics.Internal.Families
3434import Data.Generics.Internal.Lens
35+import Data.Generics.Internal.Void
3536import Data.Generics.Sum.Internal.Constructors
3637
3738import Data.Kind (Constraint, Type)
3839import GHC.Generics (Generic (Rep))
3940import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))
4041
41−-- $example
42−-- @
43−-- module Example where
44−--
45−-- import Data.Generics.Sum
46−-- import GHC.Generics
47−--
48−-- data Animal
49−-- = Dog Dog
50−-- | Cat Name Age
51−-- | Duck Age
52−-- deriving (Generic, Show)
53−--
54−-- data Dog = MkDog
55−-- { name :: Name
56−-- , age :: Age
57−-- }
58−-- deriving (Generic, Show)
59−--
60−-- type Name = String
61−-- type Age = Int
62−--
63−-- dog, cat, duck :: Animal
64−--
65−-- dog = Dog (MkDog "Shep" 3)
66−-- cat = Cat "Mog" 5
67−-- duck = Duck 2
68−-- @
42+-- $setup
43+-- >>> :set -XTypeApplications
44+-- >>> :set -XDataKinds
45+-- >>> :set -XDeriveGeneric
46+-- >>> import GHC.Generics
47+-- >>> :m +Data.Generics.Internal.Lens
48+-- >>> :{
49+-- data Animal
50+-- = Dog Dog
51+-- | Cat Name Age
52+-- | Duck Age
53+-- deriving (Generic, Show)
54+-- data Dog
55+-- = MkDog
56+-- { name :: Name
57+-- , age :: Age
58+-- }
59+-- deriving (Generic, Show)
60+-- type Name = String
61+-- type Age = Int
62+-- dog, cat, duck :: Animal
63+-- dog = Dog (MkDog "Shep" 3)
64+-- cat = Cat "Mog" 5
65+-- duck = Duck 2
66+-- :}
6967
7068-- |Sums that have a constructor with a given name.
7169class AsConstructor (ctor :: Symbol) a s | s ctor -> a where
@@ -79,10 +77,10 @@ class AsConstructor (ctor :: Symbol) a s | s ctor -> a where
7977 -- Nothing
8078 --
8179 -- >>> cat ^? _Ctor @"Cat"
82− -- Just ("Mog", 5)
80+ -- Just ("Mog",5)
8381 --
8482 -- >>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
85− -- Cat ("Garfield", 6)
83+ -- Cat "Garfield" 6
8684 _Ctor :: Prism' s a
8785
8886instance
@@ -93,6 +91,10 @@ instance
9391
9492 _Ctor = repIso . _GCtor @ctor
9593
94+-- See Note [Uncluttering type signatures]
95+instance {-# OVERLAPPING #-} AsConstructor ctor Void Void where
96+ _Ctor = undefined
97+
9698type family ErrorUnless (ctor :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
9799 ErrorUnless ctor s 'False
98100 = TypeError
src/Data/Generics/Sum/Subtype.hs+41−39
@@ -22,53 +22,47 @@
2222module Data.Generics.Sum.Subtype
2323 ( -- *Prisms
2424 --
25− -- $example
25+ -- $setup
2626 AsSubtype (..)
2727 ) where
2828
2929import Data.Generics.Internal.Lens
30+import Data.Generics.Internal.Void
3031import Data.Generics.Sum.Internal.Subtype
3132
3233import GHC.Generics (Generic (Rep, to, from))
3334
34−-- $example
35−-- @
36−-- module Example where
37−--
38−-- import Data.Generics.Sum
39−-- import GHC.Generics
40−--
41−-- data Animal
42−-- = Dog Dog
43−-- | Cat Name Age
44−-- | Duck Age
45−-- deriving (Generic, Show)
46−--
47−-- data FourLeggedAnimal
48−-- = Dog4 Dog
49−-- | Cat4 Name Age
50−-- deriving (Generic, Show)
51−--
52−-- data Dog = MkDog
53−-- { name :: Name
54−-- , age :: Age
55−-- }
56−-- deriving (Generic, Show)
57−--
58−-- type Name = String
59−-- type Age = Int
60−--
61−-- dog, cat, duck :: Animal
62−--
63−-- dog = Dog (MkDog "Shep" 3)
64−-- cat = Cat "Mog" 5
65−-- duck = Duck 2
66−--
67−-- dog4, cat4 :: FourLeggedAnimal
68−--
69−-- dog4 = Dog4 (MkDog "Snowy" 4)
70−-- cat4 = Cat4 "Garfield" 6
71−-- @
35+-- $setup
36+-- >>> :set -XTypeApplications
37+-- >>> :set -XDataKinds
38+-- >>> :set -XDeriveGeneric
39+-- >>> import GHC.Generics
40+-- >>> :m +Data.Generics.Internal.Lens
41+-- >>> :{
42+-- data Animal
43+-- = Dog Dog
44+-- | Cat Name Age
45+-- | Duck Age
46+-- deriving (Generic, Show)
47+-- data FourLeggedAnimal
48+-- = Dog4 Dog
49+-- | Cat4 Name Age
50+-- deriving (Generic, Show)
51+-- data Dog = MkDog
52+-- { name :: Name
53+-- , age :: Age
54+-- }
55+-- deriving (Generic, Show)
56+-- type Name = String
57+-- type Age = Int
58+-- dog, cat, duck :: Animal
59+-- dog = Dog (MkDog "Shep" 3)
60+-- cat = Cat "Mog" 5
61+-- duck = Duck 2
62+-- dog4, cat4 :: FourLeggedAnimal
63+-- dog4 = Dog4 (MkDog "Snowy" 4)
64+-- cat4 = Cat4 "Garfield" 6
65+-- :}
7266
7367-- |Structural subtyping between sums. A sum 'Sub' is a subtype of another sum
7468-- 'Sup' if a value of 'Sub' can be given (modulo naming of constructors)
@@ -106,3 +100,11 @@ instance
106100
107101 injectSub = to . ginjectSub . from
108102 projectSub = either (Left . to) (Right . to) . gprojectSub . from
103+
104+-- See Note [Uncluttering type signatures]
105+instance {-# OVERLAPPING #-} AsSubtype a Void where
106+ injectSub = undefined
107+ projectSub = undefined
108+instance {-# OVERLAPPING #-} AsSubtype Void a where
109+ injectSub = undefined
110+ projectSub = undefined
src/Data/Generics/Sum/Typed.hs+38−29
@@ -25,7 +25,7 @@
2525module Data.Generics.Sum.Typed
2626 ( -- *Prisms
2727 --
28− -- $example
28+ -- $setup
2929 AsType (..)
3030 ) where
3131
@@ -36,35 +36,34 @@ import Data.Generics.Sum.Internal.Typed
3636
3737import Data.Generics.Internal.Families
3838import Data.Generics.Internal.Lens
39+import Data.Generics.Internal.Void
40+
41+-- $setup
42+-- >>> :set -XTypeApplications
43+-- >>> :set -XDataKinds
44+-- >>> :set -XDeriveGeneric
45+-- >>> import GHC.Generics
46+-- >>> :m +Data.Generics.Internal.Lens
47+-- >>> :{
48+-- data Animal
49+-- = Dog Dog
50+-- | Cat Name Age
51+-- | Duck Age
52+-- deriving (Generic, Show)
53+-- data Dog
54+-- = MkDog
55+-- { name :: Name
56+-- , age :: Age
57+-- }
58+-- deriving (Generic, Show)
59+-- type Name = String
60+-- type Age = Int
61+-- dog, cat, duck :: Animal
62+-- dog = Dog (MkDog "Shep" 3)
63+-- cat = Cat "Mog" 5
64+-- duck = Duck 2
65+-- :}
3966
40−-- $example
41−-- @
42−-- module Example where
43−--
44−-- import Data.Generics.Sum
45−-- import GHC.Generics
46−--
47−-- data Animal
48−-- = Dog Dog
49−-- | Cat Name Age
50−-- | Duck Age
51−-- deriving (Generic, Show)
52−--
53−-- data Dog = MkDog
54−-- { name :: Name
55−-- , age :: Age
56−-- }
57−-- deriving (Generic, Show)
58−--
59−-- type Name = String
60−-- type Age = Int
61−--
62−-- dog, cat, duck :: Animal
63−--
64−-- dog = Dog (MkDog "Shep" 3)
65−-- cat = Cat "Mog" 5
66−-- duck = Duck 2
67−-- @
6867
6968-- |Sums that have a constructor with a field of the given type.
7069class AsType a s where
@@ -100,6 +99,16 @@ instance
10099 projectTyped
101100 = either (const Nothing) Just . gprojectTyped . from
102101
102+-- See Note [Uncluttering type signatures]
103+instance {-# OVERLAPPING #-} AsType a Void where
104+ _Typed = undefined
105+ injectTyped = undefined
106+ projectTyped = undefined
107+instance {-# OVERLAPPING #-} AsType Void a where
108+ _Typed = undefined
109+ injectTyped = undefined
110+ projectTyped = undefined
111+
103112type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constraint where
104113 ErrorUnlessOne a s 'None
105114 = TypeError
stack.yaml+1−1
@@ -1,4 +1,4 @@
1−resolver: lts-9.12
1+resolver: nightly-2017-11-25
22
33packages:
44- '.'
test/Spec.hs+18−1
@@ -28,11 +28,20 @@ data Record2 = MkRecord2
2828 { fieldA :: Int
2929 } deriving Generic
3030
31−type Lens' s a = forall f. Functor f => (a -> f a) -> s -> f s
31+data Record3 a = MkRecord3
32+ { fieldA :: a
33+ , fieldB :: Bool
34+ } deriving Generic
35+
36+type Lens' s a = Lens s s a a
37+type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
3238
3339fieldALensManual :: Lens' Record Int
3440fieldALensManual f (MkRecord a b) = (\a' -> MkRecord a' b) <$> f a
3541
42+typeChangingManual :: Lens (Record3 a) (Record3 b) a b
43+typeChangingManual f (MkRecord3 a b) = (\a' -> MkRecord3 a' b) <$> f a
44+
3645newtype L s a = L (Lens' s a)
3746
3847subtypeLensManual :: Lens' Record Record2
@@ -60,7 +69,15 @@ fieldALensPos = position @1
6069subtypeLensGeneric :: Lens' Record Record2
6170subtypeLensGeneric = super
6271
72+typeChangingGeneric :: Lens (Record3 a) (Record3 b) a b
73+typeChangingGeneric = field @"fieldA"
74+
75+typeChangingGenericPos :: Lens (Record3 a) (Record3 b) a b
76+typeChangingGenericPos = position @1
77+
6378inspect $ 'fieldALensManual === 'fieldALensName
6479inspect $ 'fieldALensManual === 'fieldALensType
6580inspect $ 'fieldALensManual === 'fieldALensPos
6681inspect $ 'subtypeLensManual === 'subtypeLensGeneric
82+inspect $ 'typeChangingManual === 'typeChangingGeneric
83+--inspect $ 'typeChangingManual === 'typeChangingGenericPos
test/doctest.hsnew file+7
@@ -0,0 +1,7 @@
1+import Test.DocTest
2+main
3+ = doctest
4+ [ "-isrc"
5+ , "src/Data/Generics/Product.hs"
6+ , "src/Data/Generics/Sum.hs"
7+ ]