on master help sign in
Merge remote-tracking branch 'lunaris/master'
28370c8Csongor Kiss
benchmarks/Bench.hsnew file+64
@@ -0,0 +1,64 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE DeriveGeneric #-}
3+{-# LANGUAGE NamedFieldPuns #-}
4+{-# LANGUAGE RankNTypes #-}
5+{-# LANGUAGE RecordWildCards #-}
6+{-# LANGUAGE TypeApplications #-}
7+
8+module Main (main) where
9+
10+import Control.DeepSeq
11+import Control.Lens.Operators
12+import Control.Lens.Type
13+import Control.Monad
14+import Criterion.Main
15+import Data.Generics.Product
16+import GHC.Generics
17+import Test.QuickCheck
18+
19+main :: IO ()
20+main = defaultMain
21+ [ env (arbitraryAnimalsOfLength 100) $ products 100
22+ , env (arbitraryAnimalsOfLength 1000) $ products 1000
23+ , env (arbitraryAnimalsOfLength 10000) $ products 10000
24+ , env (arbitraryAnimalsOfLength 100000) $ products 100000
25+ ]
26+
27+products :: Int -> [Animal] -> Benchmark
28+products n as
29+ = bgroup ("products/" ++ show n)
30+ [ bench "generic-lens/get" (nf (const $ map (^. field @"name") as) ())
31+ , bench "lens/get" (nf (const $ map (^. aName) as) ())
32+ , bench "generic-lens/set" (nf (const $ map (\a -> a & field @"name" .~ "Name") as) ())
33+ , bench "lens/set" (nf (const $ map (\a -> a & aName .~ "Name") as) ())
34+ ]
35+
36+arbitraryAnimalsOfLength :: Int -> IO [Animal]
37+arbitraryAnimalsOfLength n
38+ = replicateM n (generate arbitrary)
39+
40+data Animal = Animal
41+ { name :: String
42+ , age :: Int
43+ , eats :: String
44+ } deriving (Generic, Show)
45+
46+instance Arbitrary Animal where
47+ arbitrary = Animal <$> arbitrary <*> arbitrary <*> arbitrary
48+
49+instance NFData Animal where
50+ rnf Animal{..} = rnf name `seq` rnf age `seq` rnf eats
51+
52+aName :: Lens' Animal String
53+aName f Animal{..}
54+ = (\x -> Animal { name = x, age, eats }) <$> f name
55+
56+{-
57+aAge :: Lens' Animal Int
58+aAge f Animal{..}
59+ = (\x -> Animal { name, age = x, eats }) <$> f age
60+
61+aEats :: Lens' Animal String
62+aEats f Animal{..}
63+ = (\x -> Animal { name, age, eats = x }) <$> f eats
64+ -}
generic-lens.cabal+68−94
@@ -1,104 +1,78 @@
1−name: generic-lens
1+name: generic-lens
2−
3−version: 0.3.0.0
2+version: 0.3.0.0
4−
5−synopsis: Generic data-structure operations exposed as lenses.
3+synopsis: Generic data-structure operations exposed as lenses.
6−
7−description: 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.
4+description: 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.
8−
5+
9−homepage: https://github.com/kcsongor/generic-lens
6+homepage: https://github.com/kcsongor/generic-lens
10−
11−license: BSD3
7+license: BSD3
12−
13−license-file: LICENSE
8+license-file: LICENSE
14−
15−author: Csongor Kiss
9+author: Csongor Kiss
16−
17−maintainer: kiss.csongor.kiss@gmail.com
10+maintainer: kiss.csongor.kiss@gmail.com
18−
19−category: Generics, Records, Lens
11+category: Generics, Records, Lens
20−
21−build-type: Simple
12+build-type: Simple
22−
13+cabal-version: >= 1.10
23−-- Extra files to be distributed with the package, such as examples or a
14+
24−-- README.
25−extra-source-files: ChangeLog.md
15+extra-source-files: ChangeLog.md
26− , examples/StarWars.hs
16+ , examples/StarWars.hs
27− , examples/Examples.hs
17+ , examples/Examples.hs
28− , README.md
18+ , README.md
29−
30−-- Constraint on the version of Cabal needed to build this package.
31−cabal-version: >= 1.10
32−
33
19
34library
20library
35− exposed-modules: Data.Generics.Product
21+ exposed-modules: Data.Generics.Product
36− , Data.Generics.Product.Any
22+ , Data.Generics.Product.Any
37− , Data.Generics.Product.Fields
23+ , Data.Generics.Product.Fields
38− , Data.Generics.Product.Positions
24+ , Data.Generics.Product.Positions
39− , Data.Generics.Product.Typed
40− , Data.Generics.Product.Subtype
25+ , Data.Generics.Product.Subtype
41−
26+ , Data.Generics.Product.Typed
27+ , Data.Generics.Sum
42− , Data.Generics.Sum.HasConstructor
28+ , Data.Generics.Sum.Any
43−
29+ , Data.Generics.Sum.Constructors
30+ , Data.Generics.Sum.Typed
31+
44− , Data.Generics.Internal.Lens
32+ , Data.Generics.Internal.Lens
33+
34+ other-modules: Data.Generics.Internal.Families
35+ , Data.Generics.Internal.Families.Bool
36+ , Data.Generics.Internal.Families.Count
37+ , Data.Generics.Internal.Families.Has
38+ , Data.Generics.Internal.HList
39+
40+ build-depends: base >= 4.9 && <= 5.0
41+ , profunctors >= 5.0 && <= 6.0
42+
43+ hs-source-dirs: src
44+ default-language: Haskell2010
45+ ghc-options: -Wall -Werror
45
46
46− other-modules: Data.Generics.Internal.Families
47+source-repository head
47− , Data.Generics.Internal.Families.Count
48+ type: git
48− , Data.Generics.Internal.Families.Has
49+ location: https://github.com/kcsongor/generic-lens
49
50
50− other-extensions: AllowAmbiguousTypes
51+test-suite generic-lens-test
51− , DataKinds
52+ type: exitcode-stdio-1.0
52− , FlexibleInstances
53+ hs-source-dirs: test
53− , FunctionalDependencies
54+ main-is: Spec.hs
54− , PolyKinds
55− , Rank2Types
56− , ScopedTypeVariables
57− , TypeApplications
58− , TypeFamilies
59− , TypeOperators
60− , UndecidableInstances
61
55
62− -- Other library packages from which modules are imported.
63− build-depends: base >= 4.9 && <= 5.0
56+ build-depends: base >= 4.9 && <= 5.0
64− , profunctors >= 5.0 && <= 6.0
57+ , QuickCheck
58+ , hspec
59+ , generic-lens
65
60
66− -- Directories containing source files.
61+ default-language: Haskell2010
67− hs-source-dirs: src
62+ ghc-options: -Wall -Werror
68
63
69− -- Base language which the package is written in.
64+benchmark generic-lens-bench
70− default-language: Haskell2010
65+ type: exitcode-stdio-1.0
71− ghc-options: -Wall
66+ hs-source-dirs: benchmarks
67+ main-is: Bench.hs
72
68
73−source-repository head
74− type: git
75− location: https://github.com/kcsongor/generic-lens
76−
77−test-suite generic-lens-test
69+ build-depends: generic-lens
78− type:
79− exitcode-stdio-1.0
80− hs-source-dirs:
81− test
82− main-is:
83− Spec.hs
84
70
85− build-depends: base >= 4.9 && <= 5.0
71+ , base >= 4.9 && <= 5.0
86− , QuickCheck
72+ , QuickCheck
87− , hspec
73+ , criterion
74+ , deepseq
88− , generic-lens
75+ , lens
89
76
77+ default-language: Haskell2010
90− ghc-options:
78+ ghc-options: -Wall -Werror
91− -Wall
92− other-extensions: AllowAmbiguousTypes
93− , DataKinds
94− , FlexibleInstances
95− , FunctionalDependencies
96− , PolyKinds
97− , Rank2Types
98− , ScopedTypeVariables
99− , TypeApplications
100− , TypeFamilies
101− , TypeOperators
102− , UndecidableInstances
103− default-language:
104− Haskell2010
src/Data/Generics/Internal/Families.hs+1
@@ -2,5 +2,6 @@ module Data.Generics.Internal.Families
2 ( module Families
2 ( module Families
3 ) where
3 ) where
4
4
5+import Data.Generics.Internal.Families.Bool as Families
5import Data.Generics.Internal.Families.Count as Families
6import Data.Generics.Internal.Families.Count as Families
6import Data.Generics.Internal.Families.Has as Families
7import Data.Generics.Internal.Families.Has as Families
src/Data/Generics/Internal/Families/Bool.hsnew file+17
@@ -0,0 +1,17 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE KindSignatures #-}
3+{-# LANGUAGE TypeFamilies #-}
4+{-# LANGUAGE TypeOperators #-}
5+
6+module Data.Generics.Internal.Families.Bool
7+ ( type (||)
8+ , type (&&)
9+ ) where
10+
11+type family (a :: Bool) || (b :: Bool) :: Bool where
12+ 'True || _ = 'True
13+ _ || b = b
14+
15+type family (a :: Bool) && (b :: Bool) :: Bool where
16+ 'True && 'True = 'True
17+ _ && _ = 'False
src/Data/Generics/Internal/Families/Count.hs+42−16
@@ -5,33 +5,59 @@
5{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
6
6
7module Data.Generics.Internal.Families.Count
7module Data.Generics.Internal.Families.Count
8− ( CountType
8+ ( CountTotalType
9+ , CountPartialType
9 , Count (..)
10 , Count (..)
10 ) where
11 ) where
11
12
12import GHC.Generics
13import GHC.Generics
13import GHC.TypeLits
14import GHC.TypeLits
14
15
15−type family CountType t f :: Count where
16+type family CountTotalType t f :: Count where
16− CountType t (S1 _ (Rec0 t))
17+ CountTotalType t (S1 _ (Rec0 t))
17 = 'One
18 = 'One
18− CountType t (l :*: r)
19+ CountTotalType t (l :*: r)
19− = CountType t l <|> CountType t r
20+ = CountTotalType t l <|> CountTotalType t r
20− CountType t (l :+: r)
21+ CountTotalType t (l :+: r)
21− = CountType t l <&> CountType t r
22+ = CountTotalType t l <&> CountTotalType t r
22− CountType t (S1 _ _)
23+ CountTotalType t (S1 _ _)
23 = 'None
24 = 'None
24− CountType t (C1 _ f)
25+ CountTotalType t (C1 _ f)
25− = CountType t f
26+ = CountTotalType t f
26− CountType t (D1 _ f)
27+ CountTotalType t (D1 _ f)
27− = CountType t f
28+ = CountTotalType t f
28− CountType t (Rec0 _)
29+ CountTotalType t (Rec0 _)
29 = 'None
30 = 'None
30− CountType t U1
31+ CountTotalType t U1
31 = 'None
32 = 'None
32− CountType t V1
33+ CountTotalType t V1
33 = 'None
34 = 'None
34− CountType t f
35+ CountTotalType t f
36+ = TypeError
37+ ( 'ShowType f
38+ ':<>: 'Text " is not a valid GHC.Generics representation type"
39+ )
40+
41+type family CountPartialType t f :: Count where
42+ CountPartialType t (S1 _ (Rec0 t))
43+ = 'One
44+ CountPartialType t (l :*: r)
45+ = CountPartialType t l <|> CountPartialType t r
46+ CountPartialType t (l :+: r)
47+ = CountPartialType t l <|> CountPartialType t r
48+ CountPartialType t (S1 _ _)
49+ = 'None
50+ CountPartialType t (C1 _ f)
51+ = CountPartialType t f
52+ CountPartialType t (D1 _ f)
53+ = CountPartialType t f
54+ CountPartialType t (Rec0 _)
55+ = 'None
56+ CountPartialType t U1
57+ = 'None
58+ CountPartialType t V1
59+ = 'None
60+ CountPartialType t f
35 = TypeError
61 = TypeError
36 ( 'ShowType f
62 ( 'ShowType f
37 ':<>: 'Text " is not a valid GHC.Generics representation type"
63 ':<>: 'Text " is not a valid GHC.Generics representation type"
src/Data/Generics/Internal/Families/Has.hs+69−38
@@ -5,67 +5,98 @@
5{-# LANGUAGE UndecidableInstances #-}
5{-# LANGUAGE UndecidableInstances #-}
6
6
7module Data.Generics.Internal.Families.Has
7module Data.Generics.Internal.Families.Has
8− ( HasFieldP
8+ ( HasTotalFieldP
9− , HasTypeP
9+ , HasTotalTypeP
10+ , HasPartialTypeP
11+ , HasCtorP
10 ) where
12 ) where
11
13
14+import Data.Generics.Internal.Families.Bool
15+
12import GHC.Generics
16import GHC.Generics
13import GHC.TypeLits
17import GHC.TypeLits
14
18
15−type family HasFieldP (field :: Symbol) f :: Bool where
19+type family HasTotalFieldP (field :: Symbol) f :: Bool where
16− HasFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
20+ HasTotalFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
17 = 'True
21 = 'True
18− HasFieldP field (l :*: r)
22+ HasTotalFieldP field (l :*: r)
19− = HasFieldP field l || HasFieldP field r
23+ = HasTotalFieldP field l || HasTotalFieldP field r
20− HasFieldP field (l :+: r)
24+ HasTotalFieldP field (l :+: r)
21− = HasFieldP field l && HasFieldP field r
25+ = HasTotalFieldP field l && HasTotalFieldP field r
22− HasFieldP field (S1 _ _)
26+ HasTotalFieldP field (S1 _ _)
23 = 'False
27 = 'False
24− HasFieldP field (C1 _ f)
28+ HasTotalFieldP field (C1 _ f)
25− = HasFieldP field f
29+ = HasTotalFieldP field f
26− HasFieldP field (D1 _ f)
30+ HasTotalFieldP field (D1 _ f)
27− = HasFieldP field f
31+ = HasTotalFieldP field f
28− HasFieldP field (Rec0 _)
32+ HasTotalFieldP field (Rec0 _)
29 = 'False
33 = 'False
30− HasFieldP field U1
34+ HasTotalFieldP field U1
31 = 'False
35 = 'False
32− HasFieldP field V1
36+ HasTotalFieldP field V1
33 = 'False
37 = 'False
34− HasFieldP field f
38+ HasTotalFieldP field f
35 = TypeError
39 = TypeError
36 ( 'ShowType f
40 ( 'ShowType f
37 ':<>: 'Text " is not a valid GHC.Generics representation type"
41 ':<>: 'Text " is not a valid GHC.Generics representation type"
38 )
42 )
39
43
40−type family HasTypeP a f :: Bool where
44+type family HasTotalTypeP a f :: Bool where
41− HasTypeP t (S1 meta (Rec0 t))
45+ HasTotalTypeP t (S1 meta (Rec0 t))
42 = 'True
46 = 'True
43− HasTypeP t (l :*: r)
47+ HasTotalTypeP t (l :*: r)
44− = HasTypeP t l || HasTypeP t r
48+ = HasTotalTypeP t l || HasTotalTypeP t r
45− HasTypeP t (l :+: r)
49+ HasTotalTypeP t (l :+: r)
46− = HasTypeP t l && HasTypeP t r
50+ = HasTotalTypeP t l && HasTotalTypeP t r
47− HasTypeP t (S1 _ _)
51+ HasTotalTypeP t (S1 _ _)
48 = 'False
52 = 'False
49− HasTypeP t (C1 m f)
53+ HasTotalTypeP t (C1 m f)
50− = HasTypeP t f
54+ = HasTotalTypeP t f
51− HasTypeP t (D1 m f)
55+ HasTotalTypeP t (D1 m f)
52− = HasTypeP t f
56+ = HasTotalTypeP t f
53− HasTypeP t (Rec0 _)
57+ HasTotalTypeP t (Rec0 _)
54 = 'False
58 = 'False
55− HasTypeP t U1
59+ HasTotalTypeP t U1
56 = 'False
60 = 'False
57− HasTypeP t V1
61+ HasTotalTypeP t V1
58 = 'False
62 = 'False
59− HasTypeP t f
63+ HasTotalTypeP t f
60 = TypeError
64 = TypeError
61 ( 'ShowType f
65 ( 'ShowType f
62 ':<>: 'Text " is not a valid GHC.Generics representation type"
66 ':<>: 'Text " is not a valid GHC.Generics representation type"
63 )
67 )
64
68
65−type family (a :: Bool) || (b :: Bool) :: Bool where
69+type family HasPartialTypeP a f :: Bool where
70+ HasPartialTypeP t (S1 meta (Rec0 t))
66− 'True || _ = 'True
71+ = 'True
67− _ || b = b
72+ HasPartialTypeP t (l :*: r)
73+ = HasPartialTypeP t l || HasPartialTypeP t r
74+ HasPartialTypeP t (l :+: r)
75+ = HasPartialTypeP t l || HasPartialTypeP t r
76+ HasPartialTypeP t (S1 _ _)
77+ = 'False
78+ HasPartialTypeP t (C1 m f)
79+ = HasPartialTypeP t f
80+ HasPartialTypeP t (D1 m f)
81+ = HasPartialTypeP t f
82+ HasPartialTypeP t (Rec0 _)
83+ = 'False
84+ HasPartialTypeP t U1
85+ = 'False
86+ HasPartialTypeP t V1
87+ = 'False
88+ HasPartialTypeP t f
89+ = TypeError
90+ ( 'ShowType f
91+ ':<>: 'Text " is not a valid GHC.Generics representation type"
92+ )
68
93
69−type family (a :: Bool) && (b :: Bool) :: Bool where
94+type family HasCtorP (ctor :: Symbol) f :: Bool where
95+ HasCtorP ctor (C1 ('MetaCons ctor _ _) _)
70− 'True && 'True = 'True
96+ = 'True
97+ HasCtorP ctor (f :+: g)
98+ = HasCtorP ctor f || HasCtorP ctor g
99+ HasCtorP ctor (D1 m f)
100+ = HasCtorP ctor f
101+ HasCtorP ctor _
71− _ && _ = 'False
102+ = 'False
src/Data/Generics/Internal/HList.hsnew file+124
@@ -0,0 +1,124 @@
1+{-# LANGUAGE DataKinds #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FunctionalDependencies #-}
4+{-# LANGUAGE GADTs #-}
5+{-# LANGUAGE KindSignatures #-}
6+{-# LANGUAGE MultiParamTypeClasses #-}
7+{-# LANGUAGE PolyKinds #-}
8+{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TypeApplications #-}
10+{-# LANGUAGE TypeFamilies #-}
11+{-# LANGUAGE TypeOperators #-}
12+{-# LANGUAGE UndecidableInstances #-}
13+
14+module Data.Generics.Internal.HList
15+ ( HList (..)
16+
17+ , append
18+ , (++)
19+ , Splittable (..)
20+
21+ , ListTuple (..)
22+
23+ , GCollectible (..)
24+ ) where
25+
26+import Data.Kind
27+import GHC.Generics
28+
29+data HList (xs :: [Type]) where
30+ Nil :: HList '[]
31+ (:>) :: x -> HList xs -> HList (x ': xs)
32+
33+infixr 5 :>
34+
35+append :: HList as -> HList bs -> HList (as ++ bs)
36+append Nil ys = ys
37+append (x :> xs) ys = x :> append xs ys
38+
39+type family ((as :: [k]) ++ (bs :: [k])) :: [k] where
40+ '[] ++ bs = bs
41+ (a ': as) ++ bs = a ': as ++ bs
42+
43+class Splittable (as :: [Type]) (bs :: [Type]) (cs :: [Type]) | as bs -> cs, as cs -> bs where
44+ split :: HList cs -> (HList as, HList bs)
45+
46+instance Splittable '[] bs bs where
47+ split bs = (Nil, bs)
48+
49+instance Splittable as bs cs => Splittable (a ': as) bs (a ': cs) where
50+ split (a :> as) = let (as', bs) = split as in (a :> as', bs)
51+
52+class ListTuple (tuple :: Type) (as :: [Type]) | as -> tuple where
53+ tupleToList :: tuple -> HList as
54+ listToTuple :: HList as -> tuple
55+
56+instance ListTuple () '[] where
57+ tupleToList _ = Nil
58+ listToTuple _ = ()
59+
60+instance ListTuple a '[a] where
61+ tupleToList a = a :> Nil
62+ listToTuple (a :> Nil) = a
63+
64+instance ListTuple (a, b) '[a, b] where
65+ tupleToList (a, b) = a :> b :> Nil
66+ listToTuple (a :> b :> Nil) = (a, b)
67+
68+instance ListTuple (a, b, c) '[a, b, c] where
69+ tupleToList (a, b, c) = a :> b :> c :> Nil
70+ listToTuple (a :> b :> c :> Nil) = (a, b, c)
71+
72+instance ListTuple (a, b, c, d) '[a, b, c, d] where
73+ tupleToList (a, b, c, d) = a :> b :> c :> d:> Nil
74+ listToTuple (a :> b :> c :> d :> Nil) = (a, b, c, d)
75+
76+instance ListTuple (a, b, c, d, e) '[a, b, c, d, e] where
77+ tupleToList (a, b, c, d, e) = a :> b :> c :> d:> e :> Nil
78+ listToTuple (a :> b :> c :> d :> e :> Nil) = (a, b, c, d, e)
79+
80+instance ListTuple (a, b, c, d, e, f) '[a, b, c, d, e, f] where
81+ tupleToList (a, b, c, d, e, f) = a :> b :> c :> d:> e :> f :> Nil
82+ listToTuple (a :> b :> c :> d :> e :> f :> Nil) = (a, b, c, d, e, f)
83+
84+instance ListTuple (a, b, c, d, e, f, g) '[a, b, c, d, e, f, g] where
85+ tupleToList (a, b, c, d, e, f, g) = a :> b :> c :> d:> e :> f :> g :> Nil
86+ listToTuple (a :> b :> c :> d :> e :> f :> g :> Nil) = (a, b, c, d, e, f, g)
87+
88+instance ListTuple (a, b, c, d, e, f, g, h) '[a, b, c, d, e, f, g, h] where
89+ tupleToList (a, b, c, d, e, f, g, h) = a :> b :> c :> d:> e :> f :> g :> h :> Nil
90+ listToTuple (a :> b :> c :> d :> e :> f :> g :> h :> Nil) = (a, b, c, d, e, f, g, h)
91+
92+class GCollectible (f :: Type -> Type) (as :: [Type]) | f -> as where
93+ gtoCollection :: f x -> HList as
94+ gfromCollection :: HList as -> f x
95+
96+instance
97+ ( GCollectible l as
98+ , GCollectible r bs
99+ , cs ~ (as ++ bs)
100+ , Splittable as bs cs
101+ ) => GCollectible (l :*: r) cs where
102+
103+ gtoCollection (l :*: r) = gtoCollection l `append` gtoCollection r
104+ gfromCollection cs = let (as, bs) = split @as @bs cs in gfromCollection as :*: gfromCollection bs
105+
106+instance GCollectible (K1 R a) '[a] where
107+ gtoCollection (K1 x) = x :> Nil
108+ gfromCollection (x :> Nil) = K1 x
109+
110+instance GCollectible U1 '[] where
111+ gtoCollection U1 = Nil
112+ gfromCollection Nil = U1
113+
114+instance GCollectible f as => GCollectible (M1 S meta f) as where
115+ gtoCollection (M1 x) = gtoCollection x
116+ gfromCollection xs = M1 (gfromCollection xs)
117+
118+instance GCollectible f as => GCollectible (M1 D meta f) as where
119+ gtoCollection (M1 x) = gtoCollection x
120+ gfromCollection xs = M1 (gfromCollection xs)
121+
122+instance GCollectible f as => GCollectible (M1 C meta f) as where
123+ gtoCollection (M1 x) = gtoCollection x
124+ gfromCollection xs = M1 (gfromCollection xs)
src/Data/Generics/Product.hs+4−4
@@ -14,21 +14,21 @@
14-- be derived (see examples).
14-- be derived (see examples).
15--
15--
16-----------------------------------------------------------------------------
16-----------------------------------------------------------------------------
17+
17module Data.Generics.Product
18module Data.Generics.Product
18− ( -- * Lenses
19+ ( -- *Lenses
19 HasAny (..)
20 HasAny (..)
20
21
21 , HasField (..)
22 , HasField (..)
22 , HasPosition (..)
23 , HasPosition (..)
23 , HasType (..)
24 , HasType (..)
24
25
25− -- * Subtype relationship
26+ -- *Subtype relationships
26 , Subtype (..)
27 , Subtype (..)
27−
28 ) where
28 ) where
29
29
30import Data.Generics.Product.Any
30import Data.Generics.Product.Any
31import Data.Generics.Product.Fields
31import Data.Generics.Product.Fields
32import Data.Generics.Product.Positions
32import Data.Generics.Product.Positions
33−import Data.Generics.Product.Typed
34import Data.Generics.Product.Subtype
33import Data.Generics.Product.Subtype
34+import Data.Generics.Product.Typed
src/Data/Generics/Product/Fields.hs+7−7
@@ -36,7 +36,7 @@ module Data.Generics.Product.Fields
36import Data.Generics.Internal.Families
36import Data.Generics.Internal.Families
37import Data.Generics.Internal.Lens
37import Data.Generics.Internal.Lens
38
38
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
40import GHC.Generics
40import GHC.Generics
41import GHC.TypeLits
41import GHC.TypeLits
42
42
@@ -58,7 +58,7 @@ import GHC.TypeLits
58-- human = Human \"Tunyasz\" 50 \"London\"
58-- human = Human \"Tunyasz\" 50 \"London\"
59-- @
59-- @
60
60
61−-- | Records that have a field with a given name.
61+-- |Records that have a field with a given name.
62class HasField (field :: Symbol) a s | s field -> a where
62class HasField (field :: Symbol) a s | s field -> a where
63 -- |A lens that focuses on a field with a given name. Compatible with the
63 -- |A lens that focuses on a field with a given name. Compatible with the
64 -- lens package's 'Control.Lens.Lens' type.
64 -- lens package's 'Control.Lens.Lens' type.
@@ -71,14 +71,14 @@ class HasField (field :: Symbol) a s | s field -> a where
71 field f s
71 field f s
72 = fmap (flip (setField @field) s) (f (getField @field s))
72 = fmap (flip (setField @field) s) (f (getField @field s))
73
73
74− -- | Get 'field'
74+ -- |Get 'field'
75 --
75 --
76 -- >>> getField @"name" human
76 -- >>> getField @"name" human
77 -- "Tunyasz"
77 -- "Tunyasz"
78 getField :: s -> a
78 getField :: s -> a
79 getField s = s ^. field @field
79 getField s = s ^. field @field
80
80
81− -- | Set 'field'
81+ -- |Set 'field'
82 --
82 --
83 -- >>> setField @"age" (setField @"name" "Tamas" human) 30
83 -- >>> setField @"age" (setField @"name" "Tamas" human) 30
84 -- Human {name = "Tamas", age = 30, address = "London"}
84 -- Human {name = "Tamas", age = 30, address = "London"}
@@ -89,7 +89,7 @@ class HasField (field :: Symbol) a s | s field -> a where
89
89
90instance
90instance
91 ( Generic s
91 ( Generic s
92− , ErrorUnless field s (HasFieldP field (Rep s))
92+ , ErrorUnless field s (HasTotalFieldP field (Rep s))
93 , GHasField field (Rep s) a
93 , GHasField field (Rep s) a
94 ) => HasField field a s where
94 ) => HasField field a s where
95
95
@@ -112,10 +112,10 @@ type family ErrorUnless (field :: Symbol) (s :: Type) (contains :: Bool) :: Cons
112class GHasField (field :: Symbol) (f :: Type -> Type) a | field f -> a where
112class GHasField (field :: Symbol) (f :: Type -> Type) a | field f -> a where
113 gfield :: Lens' (f x) a
113 gfield :: Lens' (f x) a
114
114
115−instance GProductHasField field l r a (HasFieldP field l)
115+instance GProductHasField field l r a (HasTotalFieldP field l)
116 => GHasField field (l :*: r) a where
116 => GHasField field (l :*: r) a where
117
117
118− gfield = gproductField @field @_ @_ @_ @(HasFieldP field l)
118+ gfield = gproductField @field @_ @_ @_ @(HasTotalFieldP field l)
119
119
120instance (GHasField field l a, GHasField field r a)
120instance (GHasField field l a, GHasField field r a)
121 => GHasField field (l :+: r) a where
121 => GHasField field (l :+: r) a where
src/Data/Generics/Product/Positions.hs+1−1
@@ -36,7 +36,7 @@ module Data.Generics.Product.Positions
36
36
37import Data.Generics.Internal.Lens
37import Data.Generics.Internal.Lens
38
38
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
40import GHC.Generics
40import GHC.Generics
41import GHC.TypeLits
41import GHC.TypeLits
42
42
src/Data/Generics/Product/Subtype.hs+5−6
@@ -53,12 +53,11 @@ module Data.Generics.Product.Subtype
53 ( Subtype (..)
53 ( Subtype (..)
54 ) where
54 ) where
55
55
56−import Data.Generics.Product.Fields
56+import Data.Generics.Internal.Families
57−import Data.Generics.Internal.Families.Has (HasFieldP)
58−
59import Data.Generics.Internal.Lens
57import Data.Generics.Internal.Lens
58+import Data.Generics.Product.Fields
60
59
61−import Data.Kind (Type)
60+import Data.Kind
62import GHC.Generics
61import GHC.Generics
63
62
64-- |Structural subtype relationship
63-- |Structural subtype relationship
@@ -139,10 +138,10 @@ instance (GSmash a sup, GSmash b sup) => GSmash (a :*: b) sup where
139
138
140instance
139instance
141 ( leaf ~ (S1 ('MetaSel ('Just field) p f b) t)
140 ( leaf ~ (S1 ('MetaSel ('Just field) p f b) t)
142− , GSmashLeaf leaf sup (HasFieldP field sup)
141+ , GSmashLeaf leaf sup (HasTotalFieldP field sup)
143 ) => GSmash (S1 ('MetaSel ('Just field) p f b) t) sup where
142 ) => GSmash (S1 ('MetaSel ('Just field) p f b) t) sup where
144
143
145− gsmash = gsmashLeaf @_ @_ @(HasFieldP field sup)
144+ gsmash = gsmashLeaf @_ @_ @(HasTotalFieldP field sup)
146
145
147instance GSmash sub sup => GSmash (C1 c sub) sup where
146instance GSmash sub sup => GSmash (C1 c sub) sup where
148 gsmash sup (M1 sub) = M1 (gsmash sup sub)
147 gsmash sup (M1 sub) = M1 (gsmash sup sub)
src/Data/Generics/Product/Typed.hs+4−4
@@ -36,7 +36,7 @@ module Data.Generics.Product.Typed
36import Data.Generics.Internal.Families
36import Data.Generics.Internal.Families
37import Data.Generics.Internal.Lens
37import Data.Generics.Internal.Lens
38
38
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
40import GHC.Generics
40import GHC.Generics
41import GHC.TypeLits
41import GHC.TypeLits
42
42
@@ -81,7 +81,7 @@ class HasType a s where
81
81
82instance
82instance
83 ( Generic s
83 ( Generic s
84− , ErrorUnlessOne a s (CountType a (Rep s))
84+ , ErrorUnlessOne a s (CountTotalType a (Rep s))
85 , GHasType (Rep s) a
85 , GHasType (Rep s) a
86 ) => HasType a s where
86 ) => HasType a s where
87
87
@@ -113,10 +113,10 @@ type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constrain
113class GHasType (f :: Type -> Type) a where
113class GHasType (f :: Type -> Type) a where
114 gtyped :: Lens' (f x) a
114 gtyped :: Lens' (f x) a
115
115
116−instance GProductHasType l r a (HasTypeP a l)
116+instance GProductHasType l r a (HasTotalTypeP a l)
117 => GHasType (l :*: r) a where
117 => GHasType (l :*: r) a where
118
118
119− gtyped = gproductTyped @_ @_ @_ @(HasTypeP a l)
119+ gtyped = gproductTyped @_ @_ @_ @(HasTotalTypeP a l)
120
120
121instance (GHasType l a, GHasType r a) => GHasType (l :+: r) a where
121instance (GHasType l a, GHasType r a) => GHasType (l :+: r) a where
122 gtyped = combine (gtyped @l) (gtyped @r)
122 gtyped = combine (gtyped @l) (gtyped @r)
src/Data/Generics/Sum.hs+25−2
@@ -1,5 +1,28 @@
1+-----------------------------------------------------------------------------
2+-- |
3+-- Module : Data.Generics.Product
4+-- Copyright : (C) 2017 Csongor Kiss
5+-- License : BSD3
6+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
7+-- Stability : experimental
8+-- Portability : non-portable
9+--
10+-- Magic sum operations using Generics
11+--
12+-- These classes need not be instantiated manually, as GHC can automatically
13+-- prove valid instances via Generics. Only the `Generic` class needs to
14+-- be derived (see examples).
15+--
16+-----------------------------------------------------------------------------
17+
1module Data.Generics.Sum
18module Data.Generics.Sum
2− ( module HasConstructor
19+ ( -- *Prisms
20+ AsAny (..)
21+
22+ , AsConstructor (..)
23+ , AsType (..)
3 ) where
24 ) where
4
25
5−import Data.Generics.Sum.HasConstructor as HasConstructor
26+import Data.Generics.Sum.Any
27+import Data.Generics.Sum.Constructors
28+import Data.Generics.Sum.Typed
src/Data/Generics/Sum/Any.hsnew file+87
@@ -0,0 +1,87 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE FlexibleInstances #-}
3+{-# LANGUAGE FunctionalDependencies #-}
4+{-# LANGUAGE MultiParamTypeClasses #-}
5+{-# LANGUAGE PolyKinds #-}
6+{-# LANGUAGE ScopedTypeVariables #-}
7+{-# LANGUAGE TypeApplications #-}
8+{-# LANGUAGE UndecidableInstances #-}
9+
10+-----------------------------------------------------------------------------
11+-- |
12+-- Module : Data.Generics.Product.Any
13+-- Copyright : (C) 2017 Csongor Kiss
14+-- License : BSD3
15+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
16+-- Stability : experimental
17+-- Portability : non-portable
18+--
19+-- Derive a variety of prisms generically.
20+--
21+-----------------------------------------------------------------------------
22+
23+module Data.Generics.Sum.Any
24+ ( -- *Prisms
25+ --
26+ -- $example
27+ AsAny (..)
28+ ) where
29+
30+import Data.Generics.Internal.Lens
31+import Data.Generics.Sum.Constructors
32+import Data.Generics.Sum.Typed
33+
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 Dog = MkDog
48+-- { name :: Name
49+-- , age :: Age
50+-- }
51+-- deriving (Generic, Show)
52+--
53+-- type Name = String
54+-- type Age = Int
55+--
56+-- dog, cat, duck :: Animal
57+--
58+-- dog = Dog (MkDog "Shep" 3)
59+-- cat = Cat ("Mog", 5)
60+-- duck = Duck 2
61+-- @
62+
63+-- |Sums that have generic prisms.
64+class AsAny (sel :: k) a s | s sel k -> a where
65+ -- |A prism that projects a sum as identified by some selector. Currently
66+ -- supported selectors are constructor names and unique types. Compatible
67+ -- with the lens package's 'Control.Lens.Prism' type.
68+ --
69+ -- >>> dog ^? _As @"Dog"
70+ -- Just (MkDog {name = "Shep", age = 3})
71+ -- >>> dog ^? _As @Dog
72+ -- Just (MkDog {name = "Shep", age = 3})
73+ -- >>> dog ^? _As @"Cat"
74+ -- Nothing
75+ -- >>> cat ^? _As @"Cat"
76+ -- Just ("Mog", 5)
77+ -- >>> _As @"Cat" # ("Garfield", 6) :: Animal
78+ -- Cat ("Garfield", 6)
79+ -- >>> duck ^? _As @Age
80+ -- Just 2
81+ _As :: Prism' s a
82+
83+instance AsConstructor ctor a s => AsAny ctor a s where
84+ _As = _Ctor @ctor
85+
86+instance AsType a s => AsAny a a s where
87+ _As = _Typed @a
src/Data/Generics/Sum/Constructors.hsnew file+136
@@ -0,0 +1,136 @@
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 #-}
12+
13+-----------------------------------------------------------------------------
14+-- |
15+-- Module : Data.Generics.Product.Any
16+-- Copyright : (C) 2017 Csongor Kiss
17+-- License : BSD3
18+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
19+-- Stability : experimental
20+-- Portability : non-portable
21+--
22+-- Derive constructor-name-based prisms generically.
23+--
24+-----------------------------------------------------------------------------
25+
26+module Data.Generics.Sum.Constructors
27+ ( -- *Prisms
28+
29+ -- $example
30+ AsConstructor (..)
31+
32+ -- *Internals
33+ , GAsConstructor (..)
34+ ) where
35+
36+import Data.Generics.Internal.Families
37+import Data.Generics.Internal.HList
38+import Data.Generics.Internal.Lens
39+
40+import Data.Kind
41+import GHC.Generics
42+import GHC.TypeLits
43+
44+-- $example
45+-- @
46+-- module Example where
47+--
48+-- import Data.Generics.Sum
49+-- import GHC.Generics
50+--
51+-- data Animal
52+-- = Dog Dog
53+-- | Cat (Name, Age)
54+-- | Duck Age
55+-- deriving (Generic, Show)
56+--
57+-- data Dog = MkDog
58+-- { name :: Name
59+-- , age :: Age
60+-- }
61+-- deriving (Generic, Show)
62+--
63+-- type Name = String
64+-- type Age = Int
65+--
66+-- dog, cat, duck :: Animal
67+--
68+-- dog = Dog (MkDog "Shep" 3)
69+-- cat = Cat ("Mog", 5)
70+-- duck = Duck 2
71+-- @
72+
73+-- |Sums that have a constructor with a given name.
74+class AsConstructor (ctor :: Symbol) a s | s ctor -> a where
75+ -- |A prism that projects a named constructor from a sum. Compatible with the
76+ -- lens package's 'Control.Lens.Prism' type.
77+ --
78+ -- >>> dog ^? _Ctor @"Dog"
79+ -- Just (MkDog {name = "Shep", age = 3})
80+ -- >>> dog ^? _Ctor @"Cat"
81+ -- Nothing
82+ -- >>> cat ^? _Ctor @"Cat"
83+ -- Just ("Mog", 5)
84+ -- >>> _Ctor @"Cat" # ("Garfield", 6) :: Animal
85+ -- Cat ("Garfield", 6)
86+ _Ctor :: Prism' s a
87+
88+instance
89+ ( Generic s
90+ , ErrorUnless ctor s (HasCtorP ctor (Rep s))
91+ , GAsConstructor ctor (Rep s) a
92+ ) => AsConstructor ctor a s where
93+
94+ _Ctor = repIso . _GCtor @ctor
95+
96+type family ErrorUnless (ctor :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
97+ ErrorUnless ctor s 'False
98+ = TypeError
99+ ( 'Text "The type "
100+ ':<>: 'ShowType s
101+ ':<>: 'Text " does not contain a constructor named "
102+ ':<>: 'ShowType ctor
103+ )
104+
105+ ErrorUnless _ _ 'True
106+ = ()
107+
108+-- |As 'AsConstructor' but over generic representations as defined by
109+-- "GHC.Generics".
110+class GAsConstructor (ctor :: Symbol) (f :: Type -> Type) a | ctor f -> a where
111+ _GCtor :: Prism' (f x) a
112+
113+instance
114+ ( GCollectible f as
115+ , ListTuple a as
116+ ) => GAsConstructor ctor (M1 C ('MetaCons ctor fixity fields) f) a where
117+
118+ _GCtor = prism (M1 . gfromCollection . tupleToList) (Right . listToTuple @_ @as . gtoCollection . unM1)
119+
120+instance GSumAsConstructor ctor l r a (HasCtorP ctor l) => GAsConstructor ctor (l :+: r) a where
121+ _GCtor = _GSumCtor @ctor @l @r @a @(HasCtorP ctor l)
122+
123+instance GAsConstructor ctor f a => GAsConstructor ctor (M1 D meta f) a where
124+ _GCtor = mIso . _GCtor @ctor
125+
126+instance GAsConstructor ctor f a => GAsConstructor ctor (M1 S meta f) a where
127+ _GCtor = mIso . _GCtor @ctor
128+
129+class GSumAsConstructor (ctor :: Symbol) l r a (contains :: Bool) | ctor l r contains -> a where
130+ _GSumCtor :: Prism' ((l :+: r) x) a
131+
132+instance GAsConstructor ctor l a => GSumAsConstructor ctor l r a 'True where
133+ _GSumCtor = left . _GCtor @ctor
134+
135+instance GAsConstructor ctor r a => GSumAsConstructor ctor l r a 'False where
136+ _GSumCtor = right . _GCtor @ctor
src/Data/Generics/Sum/HasConstructor.hsdeleted−255
@@ -1,255 +0,0 @@
1−{-# LANGUAGE AllowAmbiguousTypes #-}
2−{-# LANGUAGE DataKinds #-}
3−{-# LANGUAGE FlexibleInstances #-}
4−{-# LANGUAGE FunctionalDependencies #-}
5−{-# LANGUAGE GADTs #-}
6−{-# LANGUAGE InstanceSigs #-}
7−{-# LANGUAGE PolyKinds #-}
8−{-# LANGUAGE Rank2Types #-}
9−{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE TypeApplications #-}
11−{-# LANGUAGE TypeFamilies #-}
12−{-# LANGUAGE TypeOperators #-}
13−{-# LANGUAGE UndecidableInstances #-}
14−
15−-----------------------------------------------------------------------------
16−-- |
17−-- Module : Data.Generics.Sum.HasConstructor
18−-- Copyright : (C) 2017 Csongor Kiss
19−-- License : BSD3
20−-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
21−-- Stability : experimental
22−-- Portability : non-portable
23−--
24−-- Derive prisms generically
25−--
26−-- @
27−--
28−-- data FooBar
29−-- = Foo Int
30−-- | Bar Int String
31−-- | Baz (Int, String)
32−-- | Qux
33−-- deriving (Show, Generic)
34−--
35−-- @
36−--
37−-- >>> Bar 5 "coconut" ^? as @"Bar"
38−-- Just (5, "coconut")
39−--
40−-- >>> Qux ^? as @"Qux"
41−-- Just ()
42−--
43−-- >>> as @"Bar" # (5, "asd") :: FooBar
44−-- Bar 5 "asd"
45−--
46−
47−-----------------------------------------------------------------------------
48−
49−module Data.Generics.Sum.HasConstructor
50− ( HasConstructor (..)
51− ) where
52−
53−import Data.Generics.Internal.Lens
54−
55−import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))
56−import Data.Kind (Type, Constraint)
57−import GHC.Generics
58−
59−class HasConstructor (con :: Symbol) a s | s con -> a where
60− as :: Prism' s a
61−
62−instance
63− ( Generic s
64− , ErrorUnless (ContainsC con (Rep s)) con s
65− , GHasConstructor con (Rep s) a
66− ) => HasConstructor con a s where
67− as = repIso . gconstruct @con
68−
69−--------------------------------------------------------------------------------
70−
71−type family ErrorUnless (contains :: Bool) (con :: Symbol) (s :: *) :: Constraint where
72− ErrorUnless 'False con s
73− = TypeError ( 'ShowType s
74− ':<>: 'Text " has no constructor with name "
75− ':<>: 'ShowType con)
76− ErrorUnless _ _ _
77− = ()
78−
79−--------------------------------------------------------------------------------
80−
81−data HList (xs :: [Type]) where
82− Nil :: HList '[]
83− (:>) :: x -> HList xs -> HList (x ': xs)
84−
85−infixr 5 :>
86−
87−append :: HList xs -> HList ys -> HList (xs ++ ys)
88−append Nil ys = ys
89−append (x :> xs) ys = x :> (xs `append` ys)
90−
91−class AsList (tup :: *) (xs :: [*]) | xs -> tup where
92− asList :: tup -> HList xs
93− asTuple :: HList xs -> tup
94−
95−instance AsList () '[] where
96− asList _
97− = Nil
98−
99− asTuple _
100− = ()
101−
102−instance AsList a '[a] where
103− asList a
104− = a :> Nil
105−
106− asTuple (a :> Nil)
107− = a
108−
109−instance AsList (a, b) '[a, b] where
110− asList (a, b)
111− = a :> b :> Nil
112−
113− asTuple (a :> b :> Nil)
114− = (a, b)
115−
116−instance AsList (a, b, c) '[a, b, c] where
117− asList (a, b, c)
118− = a :> b :> c :> Nil
119−
120− asTuple (a :> b :> c :> Nil)
121− = (a, b, c)
122−
123−instance AsList (a, b, c, d) '[a, b, c, d] where
124− asList (a, b, c, d)
125− = a :> b :> c :> d :> Nil
126−
127− asTuple (a :> b :> c :> d :> Nil)
128− = (a, b, c, d)
129−
130−instance AsList (a, b, c, d, e) '[a, b, c, d, e] where
131− asList (a, b, c, d, e)
132− = a :> b :> c :> d :> e :> Nil
133−
134− asTuple (a :> b :> c :> d :> e :> Nil)
135− = (a, b, c, d, e)
136−
137−instance AsList (a, b, c, d, e, f) '[a, b, c, d, e, f] where
138− asList (a, b, c, d, e, f)
139− = a :> b :> c :> d :> e :> f :> Nil
140−
141− asTuple (a :> b :> c :> d :> e :> f :> Nil)
142− = (a, b, c, d, e, f)
143−
144−instance AsList (a, b, c, d, e, f, g) '[a, b, c, d, e, f, g] where
145− asList (a, b, c, d, e, f, g)
146− = a :> b :> c :> d :> e :> f :> g :> Nil
147−
148− asTuple (a :> b :> c :> d :> e :> f :> g :> Nil)
149− = (a, b, c, d, e, f, g)
150−
151−instance AsList (a, b, c, d, e, f, g, h) '[a, b, c, d, e, f, g, h] where
152− asList (a, b, c, d, e, f, g, h)
153− = a :> b :> c :> d :> e :> f :> g :> h :> Nil
154−
155− asTuple (a :> b :> c :> d :> e :> f :> g :> h :> Nil)
156− = (a, b, c, d, e, f, g, h)
157−
158−type family ((xs :: [k]) ++ (ys :: [k])) :: [k] where
159− '[] ++ ys = ys
160− (x ': xs) ++ ys = x ': xs ++ ys
161−
162−--------------------------------------------------------------------------------
163−
164−class GHasConstructor (con :: Symbol) (s :: Type -> Type) a | con s -> a where
165− gconstruct :: Prism' (s x) a
166−
167−instance GHasConstructor con s a => GHasConstructor con (M1 D c s) a where
168− gconstruct = mIso . gconstruct @con
169−
170−instance (GCollect s xs, AsList a xs) => GHasConstructor con (M1 C ('MetaCons con f n) s) a where
171− gconstruct = prism (M1 . gto . asList) (Right . asTuple @_ @xs . gfrom . unM1)
172−
173−instance (GHasConstructor con s a) => GHasConstructor con (M1 S m s) a where
174− gconstruct = mIso . gconstruct @con
175−
176−class GHasConstructorSum (con :: Symbol) l r a (p :: Bool) | con l r p -> a where
177− gconstructSum :: Prism' ((l :+: r) x) a
178−
179−instance GHasConstructor con l a => GHasConstructorSum con l r a 'True where
180− gconstructSum = left . gconstruct @con
181−
182−instance GHasConstructor con r a => GHasConstructorSum con l r a 'False where
183− gconstructSum = right . gconstruct @con
184−
185−instance GHasConstructorSum con l r a (ContainsC con l) => GHasConstructor con (l :+: r) a where
186− gconstruct = gconstructSum @con @l @r @a @(ContainsC con l)
187−
188−--------------------------------------------------------------------------------
189−-- * Split is the inverse of append
190−
191−class Split xs ys zs | xs ys -> zs, xs zs -> ys where
192− split :: HList zs -> (HList xs, HList ys)
193−
194−instance Split '[] xs xs where
195− split xs = (Nil, xs)
196−
197−instance Split xs ys zs => Split (x ': xs) ys (x ': zs) where
198− split (x :> xs) = (x :> xs', ys')
199− where (xs', ys') = split xs
200−
201−--------------------------------------------------------------------------------
202−
203−-- | Collect parameters of a constructor into an HList
204−class GCollect (s :: Type -> Type) (xs :: [Type]) | s -> xs where
205− gfrom :: s x -> HList xs
206− gto :: HList xs -> s x
207−
208−instance
209− ( GCollect a as
210− , GCollect b bs
211− , xs ~ (as ++ bs)
212− , Split as bs xs
213− ) => GCollect (a :*: b) xs where
214−
215− gfrom (a :*: b) = gfrom a `append` gfrom b
216− gto xs = gto l :*: gto r
217− where (l, r) = split @as @bs xs
218−
219−instance GCollect (K1 R a) '[a] where
220− gfrom (K1 x) = x :> Nil
221− gto (x :> Nil) = K1 x
222−
223−instance GCollect U1 '[] where
224− gfrom U1 = Nil
225− gto Nil = U1
226−
227−instance GCollect s a => GCollect (M1 S c s) a where
228− gfrom (M1 x) = gfrom x
229− gto x = M1 $ gto x
230−
231−instance GCollect s a => GCollect (M1 D c s) a where
232− gfrom (M1 x) = gfrom x
233− gto x = M1 $ gto x
234−
235−instance GCollect s a => GCollect (M1 C c s) a where
236− gfrom (M1 x) = gfrom x
237− gto x = M1 $ gto x
238−
239−--------------------------------------------------------------------------------
240−
241−type family ContainsC (cname :: Symbol) f :: Bool where
242− ContainsC cname (C1 ('MetaCons cname _ _) _)
243− = 'True
244− ContainsC cname (f :+: g)
245− = ContainsC cname f || ContainsC cname g
246− ContainsC cname (D1 m f)
247− = ContainsC cname f
248− ContainsC cname _
249− = 'False
250−
251−-- | Type-level alternative
252−type family (a :: Bool) || (b :: Bool) :: Bool where
253− 'True || _ = 'True
254− 'False || b = b
255−
src/Data/Generics/Sum/Typed.hsnew file+142
@@ -0,0 +1,142 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleContexts #-}
4+{-# LANGUAGE FlexibleInstances #-}
5+{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE KindSignatures #-}
7+{-# LANGUAGE MultiParamTypeClasses #-}
8+{-# LANGUAGE ScopedTypeVariables #-}
9+{-# LANGUAGE TypeApplications #-}
10+{-# LANGUAGE TypeFamilies #-}
11+{-# LANGUAGE TypeOperators #-}
12+{-# LANGUAGE UndecidableInstances #-}
13+
14+-----------------------------------------------------------------------------
15+-- |
16+-- Module : Data.Generics.Product.Any
17+-- Copyright : (C) 2017 Csongor Kiss
18+-- License : BSD3
19+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
20+-- Stability : experimental
21+-- Portability : non-portable
22+--
23+-- Derive constructor-field-type-based prisms generically.
24+--
25+-----------------------------------------------------------------------------
26+
27+module Data.Generics.Sum.Typed
28+ ( -- *Prisms
29+ --
30+ -- $example
31+ AsType (..)
32+
33+ -- *Internals
34+ , GAsType (..)
35+ ) where
36+
37+import Data.Generics.Internal.Families
38+import Data.Generics.Internal.HList
39+import Data.Generics.Internal.Lens
40+
41+import Data.Kind
42+import GHC.Generics
43+import GHC.TypeLits
44+
45+-- $example
46+-- @
47+-- module Example where
48+--
49+-- import Data.Generics.Sum
50+-- import GHC.Generics
51+--
52+-- data Animal
53+-- = Dog Dog
54+-- | Cat (Name, Age)
55+-- | Duck Age
56+-- deriving (Generic, Show)
57+--
58+-- data Dog = MkDog
59+-- { name :: Name
60+-- , age :: Age
61+-- }
62+-- deriving (Generic, Show)
63+--
64+-- type Name = String
65+-- type Age = Int
66+--
67+-- dog, cat, duck :: Animal
68+--
69+-- dog = Dog (MkDog "Shep" 3)
70+-- cat = Cat ("Mog", 5)
71+-- duck = Duck 2
72+-- @
73+
74+-- |Sums that have a constructor with a field of the given type.
75+class AsType a s where
76+ -- |A prism that projects a constructor uniquely identifiable by the type of
77+ -- its field. Compatible with the lens package's 'Control.Lens.Prism' type.
78+ --
79+ -- >>> dog ^? _Typed @Dog
80+ -- Just (MkDog {name = "Shep", age = 3})
81+ -- >>> dog ^? _Typed @Cat
82+ -- Nothing
83+ -- >>> duck ^? _Typed @Age
84+ -- Just 2
85+ _Typed :: Prism' s a
86+
87+instance
88+ ( Generic s
89+ , ErrorUnlessOne a s (CountPartialType a (Rep s))
90+ , GAsType (Rep s) a
91+ ) => AsType a s where
92+
93+ _Typed = repIso . _GTyped
94+
95+type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constraint where
96+ ErrorUnlessOne a s 'None
97+ = TypeError
98+ ( 'Text "The type "
99+ ':<>: 'ShowType s
100+ ':<>: 'Text " does not contain a constructor whose field is of type "
101+ ':<>: 'ShowType a
102+ )
103+
104+ ErrorUnlessOne a s 'Multiple
105+ = TypeError
106+ ( 'Text "The type "
107+ ':<>: 'ShowType s
108+ ':<>: 'Text " contains multiple constructors whose fields are of type "
109+ ':<>: 'ShowType a
110+ ':<>: 'Text "; the choice of constructor is thus ambiguous"
111+ )
112+
113+ ErrorUnlessOne _ _ 'One
114+ = ()
115+
116+-- |As 'AsType' but over generic representations as defined by "GHC.Generics".
117+class GAsType (f :: Type -> Type) a where
118+ _GTyped :: Prism' (f x) a
119+
120+instance
121+ ( GCollectible f '[a]
122+ ) => GAsType (M1 C meta f) a where
123+
124+ _GTyped = prism (M1 . gfromCollection . tupleToList) (Right . listToTuple @_ @'[a] . gtoCollection . unM1)
125+
126+instance GSumAsType l r a (HasPartialTypeP a l) => GAsType (l :+: r) a where
127+ _GTyped = _GSumTyped @l @r @a @(HasPartialTypeP a l)
128+
129+instance GAsType f a => GAsType (M1 D meta f) a where
130+ _GTyped = mIso . _GTyped
131+
132+instance GAsType f a => GAsType (M1 S meta f) a where
133+ _GTyped = mIso . _GTyped
134+
135+class GSumAsType l r a (contains :: Bool) where
136+ _GSumTyped :: Prism' ((l :+: r) x) a
137+
138+instance GAsType l a => GSumAsType l r a 'True where
139+ _GSumTyped = left . _GTyped
140+
141+instance GAsType r a => GSumAsType l r a 'False where
142+ _GSumTyped = right . _GTyped