on master help sign in
Add prisms and their magic Any too.
4a424e1Will Jones
generic-lens.cabal+9−2
@@ -36,16 +36,23 @@ library
36 , Data.Generics.Product.Any
36 , Data.Generics.Product.Any
37 , Data.Generics.Product.Fields
37 , Data.Generics.Product.Fields
38 , Data.Generics.Product.Positions
38 , Data.Generics.Product.Positions
39− , Data.Generics.Product.Typed
40 , Data.Generics.Product.Subtype
39 , Data.Generics.Product.Subtype
40+ , Data.Generics.Product.Typed
41+ , Data.Generics.Sum.Any
42+ , Data.Generics.Sum.Constructors
43+ , Data.Generics.Sum.Typed
41
44
42− , Data.Generics.Sum.HasConstructor
45+ , Data.Generics.Record
46+ , Data.Generics.Record.Subtype
47+ , Data.Generics.Internal.Lens
43
48
44 , Data.Generics.Internal.Lens
49 , Data.Generics.Internal.Lens
45
50
46 other-modules: Data.Generics.Internal.Families
51 other-modules: Data.Generics.Internal.Families
52+ , Data.Generics.Internal.Families.Bool
47 , Data.Generics.Internal.Families.Count
53 , Data.Generics.Internal.Families.Count
48 , Data.Generics.Internal.Families.Has
54 , Data.Generics.Internal.Families.Has
55+ , Data.Generics.Internal.HList
49
56
50 other-extensions: AllowAmbiguousTypes
57 other-extensions: AllowAmbiguousTypes
51 , DataKinds
58 , DataKinds
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/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/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
@@ -89,14 +89,14 @@ class HasField (field :: Symbol) a s | s field -> a where
89
89
90instance
90instance
91 ( Generic s
91 ( Generic s
92− , ErrorUnlessJust field s (HasFieldP field (Rep s))
92+ , ErrorUnlessTrue 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
96 field = repIso . gfield @field
96 field = repIso . gfield @field
97
97
98−type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
98+type family ErrorUnlessTrue (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
99− ErrorUnlessJust field s 'False
99+ ErrorUnlessTrue field s 'False
100 = TypeError
100 = TypeError
101 ( 'Text "The type "
101 ( 'Text "The type "
102 ':<>: 'ShowType s
102 ':<>: 'ShowType s
@@ -104,7 +104,7 @@ type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) ::
104 ':<>: 'ShowType field
104 ':<>: 'ShowType field
105 )
105 )
106
106
107− ErrorUnlessJust _ _ 'True
107+ ErrorUnlessTrue _ _ 'True
108 = ()
108 = ()
109
109
110-- |As 'HasField' but over generic representations as defined by
110-- |As 'HasField' but over generic representations as defined by
@@ -112,10 +112,10 @@ type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) ::
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/Typed.hs+3−3
@@ -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
@@ -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/Any.hsnew file+25
@@ -0,0 +1,25 @@
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+module Data.Generics.Sum.Any
11+ ( AsAny (..)
12+ ) where
13+
14+import Data.Generics.Internal.Lens
15+import Data.Generics.Sum.Constructors
16+import Data.Generics.Sum.Typed
17+
18+class AsAny (sel :: k) a s | s sel k -> a where
19+ _As :: Prism' s a
20+
21+instance AsConstructor ctor a s => AsAny ctor a s where
22+ _As = _Ctor @ctor
23+
24+instance AsType a s => AsAny a a s where
25+ _As = _Typed @a
src/Data/Generics/Sum/Constructors.hsnew file+76
@@ -0,0 +1,76 @@
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+module Data.Generics.Sum.Constructors
14+ ( AsConstructor (..)
15+
16+ , GAsConstructor (..)
17+ ) where
18+
19+import Data.Generics.Internal.Families
20+import Data.Generics.Internal.HList
21+import Data.Generics.Internal.Lens
22+
23+import Data.Kind
24+import GHC.Generics
25+import GHC.TypeLits
26+
27+class AsConstructor (ctor :: Symbol) a s | s ctor -> a where
28+ _Ctor :: Prism' s a
29+
30+instance
31+ ( Generic s
32+ , ErrorUnlessTrue ctor s (HasCtorP ctor (Rep s))
33+ , GAsConstructor ctor (Rep s) a
34+ ) => AsConstructor ctor a s where
35+
36+ _Ctor = repIso . _GCtor @ctor
37+
38+type family ErrorUnlessTrue (ctor :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
39+ ErrorUnlessTrue ctor s 'False
40+ = TypeError
41+ ( 'Text "The type "
42+ ':<>: 'ShowType s
43+ ':<>: 'Text " does not contain a constructor named "
44+ ':<>: 'ShowType ctor
45+ )
46+
47+ ErrorUnlessTrue _ _ 'True
48+ = ()
49+
50+class GAsConstructor (ctor :: Symbol) (f :: Type -> Type) a | ctor f -> a where
51+ _GCtor :: Prism' (f x) a
52+
53+instance
54+ ( GCollectible f as
55+ , ListTuple a as
56+ ) => GAsConstructor ctor (M1 C ('MetaCons ctor fixity fields) f) a where
57+
58+ _GCtor = prism (M1 . gfromCollection . tupleToList) (Right . listToTuple @_ @as . gtoCollection . unM1)
59+
60+instance GSumAsConstructor ctor l r a (HasCtorP ctor l) => GAsConstructor ctor (l :+: r) a where
61+ _GCtor = _GSumCtor @ctor @l @r @a @(HasCtorP ctor l)
62+
63+instance GAsConstructor ctor f a => GAsConstructor ctor (M1 D meta f) a where
64+ _GCtor = mIso . _GCtor @ctor
65+
66+instance GAsConstructor ctor f a => GAsConstructor ctor (M1 S meta f) a where
67+ _GCtor = mIso . _GCtor @ctor
68+
69+class GSumAsConstructor (ctor :: Symbol) l r a (contains :: Bool) | ctor l r contains -> a where
70+ _GSumCtor :: Prism' ((l :+: r) x) a
71+
72+instance GAsConstructor ctor l a => GSumAsConstructor ctor l r a 'True where
73+ _GSumCtor = left . _GCtor @ctor
74+
75+instance GAsConstructor ctor r a => GSumAsConstructor ctor l r a 'False where
76+ _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+76
@@ -0,0 +1,76 @@
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+module Data.Generics.Sum.Typed
15+ ( AsType (..)
16+
17+ , GAsType (..)
18+ ) where
19+
20+import Data.Generics.Internal.Families
21+import Data.Generics.Internal.HList
22+import Data.Generics.Internal.Lens
23+
24+import Data.Kind
25+import GHC.Generics
26+import GHC.TypeLits
27+
28+class AsType a s where
29+ _Typed :: Prism' s a
30+
31+instance
32+ ( Generic s
33+ , ErrorUnlessTrue a s (HasPartialTypeP a (Rep s))
34+ , GAsType (Rep s) a
35+ ) => AsType a s where
36+
37+ _Typed = repIso . _GTyped
38+
39+type family ErrorUnlessTrue (a :: Type) (s :: Type) (contains :: Bool) :: Constraint where
40+ ErrorUnlessTrue a s 'False
41+ = TypeError
42+ ( 'Text "The type "
43+ ':<>: 'ShowType s
44+ ':<>: 'Text " does not contain a constructor whose field is of type "
45+ ':<>: 'ShowType a
46+ )
47+
48+ ErrorUnlessTrue _ _ 'True
49+ = ()
50+
51+class GAsType (f :: Type -> Type) a where
52+ _GTyped :: Prism' (f x) a
53+
54+instance
55+ ( GCollectible f '[a]
56+ ) => GAsType (M1 C meta f) a where
57+
58+ _GTyped = prism (M1 . gfromCollection . tupleToList) (Right . listToTuple @_ @'[a] . gtoCollection . unM1)
59+
60+instance GSumAsType l r a (HasPartialTypeP a l) => GAsType (l :+: r) a where
61+ _GTyped = _GSumTyped @l @r @a @(HasPartialTypeP a l)
62+
63+instance GAsType f a => GAsType (M1 D meta f) a where
64+ _GTyped = mIso . _GTyped
65+
66+instance GAsType f a => GAsType (M1 S meta f) a where
67+ _GTyped = mIso . _GTyped
68+
69+class GSumAsType l r a (contains :: Bool) where
70+ _GSumTyped :: Prism' ((l :+: r) x) a
71+
72+instance GAsType l a => GSumAsType l r a 'True where
73+ _GSumTyped = left . _GTyped
74+
75+instance GAsType r a => GSumAsType l r a 'False where
76+ _GSumTyped = right . _GTyped