on master help sign in
Add prisms and their magic Any too.
commit4a424e18d19fc2472c2563b9c78904fd25c2efdf authorWill Jones <will@sacharissa.co.uk> dateMon 31 Jul 2017, 16:54 (9 years ago) parent05c49ff
12 files changed+408−306
generic-lens.cabal+9−2 src/Data/Generics/Internal/Families.hs+1 src/Data/Generics/Internal/Families/Bool.hs+17 src/Data/Generics/Internal/Families/Has.hs+69−38 src/Data/Generics/Internal/HList.hs+124 src/Data/Generics/Product/Fields.hs+7−7 src/Data/Generics/Product/Positions.hs+1−1 src/Data/Generics/Product/Typed.hs+3−3 src/Data/Generics/Sum/Any.hs+25 src/Data/Generics/Sum/Constructors.hs+76 src/Data/Generics/Sum/HasConstructor.hs−255 src/Data/Generics/Sum/Typed.hs+76
generic-lens.cabal+9−2
@@ -36,16 +36,23 @@ library
3636 , Data.Generics.Product.Any
3737 , Data.Generics.Product.Fields
3838 , Data.Generics.Product.Positions
39− , Data.Generics.Product.Typed
4039 , Data.Generics.Product.Subtype
40+ , Data.Generics.Product.Typed
41+ , Data.Generics.Sum.Any
42+ , Data.Generics.Sum.Constructors
43+ , Data.Generics.Sum.Typed
4144
42− , Data.Generics.Sum.HasConstructor
45+ , Data.Generics.Record
46+ , Data.Generics.Record.Subtype
47+ , Data.Generics.Internal.Lens
4348
4449 , Data.Generics.Internal.Lens
4550
4651 other-modules: Data.Generics.Internal.Families
52+ , Data.Generics.Internal.Families.Bool
4753 , Data.Generics.Internal.Families.Count
4854 , Data.Generics.Internal.Families.Has
55+ , Data.Generics.Internal.HList
4956
5057 other-extensions: AllowAmbiguousTypes
5158 , DataKinds
src/Data/Generics/Internal/Families.hs+1
@@ -2,5 +2,6 @@ module Data.Generics.Internal.Families
22 ( module Families
33 ) where
44
5+import Data.Generics.Internal.Families.Bool as Families
56import Data.Generics.Internal.Families.Count as Families
67import 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 @@
55{-# LANGUAGE UndecidableInstances #-}
66
77module Data.Generics.Internal.Families.Has
8− ( HasFieldP
9− , HasTypeP
8+ ( HasTotalFieldP
9+ , HasTotalTypeP
10+ , HasPartialTypeP
11+ , HasCtorP
1012 ) where
1113
14+import Data.Generics.Internal.Families.Bool
15+
1216import GHC.Generics
1317import GHC.TypeLits
1418
15−type family HasFieldP (field :: Symbol) f :: Bool where
16− HasFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
19+type family HasTotalFieldP (field :: Symbol) f :: Bool where
20+ HasTotalFieldP field (S1 ('MetaSel ('Just field) _ _ _) (Rec0 t))
1721 = 'True
18− HasFieldP field (l :*: r)
19− = HasFieldP field l || HasFieldP field r
20− HasFieldP field (l :+: r)
21− = HasFieldP field l && HasFieldP field r
22− HasFieldP field (S1 _ _)
22+ HasTotalFieldP field (l :*: r)
23+ = HasTotalFieldP field l || HasTotalFieldP field r
24+ HasTotalFieldP field (l :+: r)
25+ = HasTotalFieldP field l && HasTotalFieldP field r
26+ HasTotalFieldP field (S1 _ _)
2327 = 'False
24− HasFieldP field (C1 _ f)
25− = HasFieldP field f
26− HasFieldP field (D1 _ f)
27− = HasFieldP field f
28− HasFieldP field (Rec0 _)
28+ HasTotalFieldP field (C1 _ f)
29+ = HasTotalFieldP field f
30+ HasTotalFieldP field (D1 _ f)
31+ = HasTotalFieldP field f
32+ HasTotalFieldP field (Rec0 _)
2933 = 'False
30− HasFieldP field U1
34+ HasTotalFieldP field U1
3135 = 'False
32− HasFieldP field V1
36+ HasTotalFieldP field V1
3337 = 'False
34− HasFieldP field f
38+ HasTotalFieldP field f
3539 = TypeError
3640 ( 'ShowType f
3741 ':<>: 'Text " is not a valid GHC.Generics representation type"
3842 )
3943
40−type family HasTypeP a f :: Bool where
41− HasTypeP t (S1 meta (Rec0 t))
44+type family HasTotalTypeP a f :: Bool where
45+ HasTotalTypeP t (S1 meta (Rec0 t))
4246 = 'True
43− HasTypeP t (l :*: r)
44− = HasTypeP t l || HasTypeP t r
45− HasTypeP t (l :+: r)
46− = HasTypeP t l && HasTypeP t r
47− HasTypeP t (S1 _ _)
47+ HasTotalTypeP t (l :*: r)
48+ = HasTotalTypeP t l || HasTotalTypeP t r
49+ HasTotalTypeP t (l :+: r)
50+ = HasTotalTypeP t l && HasTotalTypeP t r
51+ HasTotalTypeP t (S1 _ _)
4852 = 'False
49− HasTypeP t (C1 m f)
50− = HasTypeP t f
51− HasTypeP t (D1 m f)
52− = HasTypeP t f
53− HasTypeP t (Rec0 _)
53+ HasTotalTypeP t (C1 m f)
54+ = HasTotalTypeP t f
55+ HasTotalTypeP t (D1 m f)
56+ = HasTotalTypeP t f
57+ HasTotalTypeP t (Rec0 _)
5458 = 'False
55− HasTypeP t U1
59+ HasTotalTypeP t U1
5660 = 'False
57− HasTypeP t V1
61+ HasTotalTypeP t V1
5862 = 'False
59− HasTypeP t f
63+ HasTotalTypeP t f
6064 = TypeError
6165 ( 'ShowType f
6266 ':<>: 'Text " is not a valid GHC.Generics representation type"
6367 )
6468
65−type family (a :: Bool) || (b :: Bool) :: Bool where
66− 'True || _ = 'True
67− _ || b = b
69+type family HasPartialTypeP a f :: Bool where
70+ HasPartialTypeP t (S1 meta (Rec0 t))
71+ = 'True
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+ )
6893
69−type family (a :: Bool) && (b :: Bool) :: Bool where
70− 'True && 'True = 'True
71− _ && _ = 'False
94+type family HasCtorP (ctor :: Symbol) f :: Bool where
95+ HasCtorP ctor (C1 ('MetaCons ctor _ _) _)
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 _
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
3636import Data.Generics.Internal.Families
3737import Data.Generics.Internal.Lens
3838
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
4040import GHC.Generics
4141import GHC.TypeLits
4242
@@ -89,14 +89,14 @@ class HasField (field :: Symbol) a s | s field -> a where
8989
9090instance
9191 ( Generic s
92− , ErrorUnlessJust field s (HasFieldP field (Rep s))
92+ , ErrorUnlessTrue field s (HasTotalFieldP field (Rep s))
9393 , GHasField field (Rep s) a
9494 ) => HasField field a s where
9595
9696 field = repIso . gfield @field
9797
98−type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
99− ErrorUnlessJust field s 'False
98+type family ErrorUnlessTrue (field :: Symbol) (s :: Type) (contains :: Bool) :: Constraint where
99+ ErrorUnlessTrue field s 'False
100100 = TypeError
101101 ( 'Text "The type "
102102 ':<>: 'ShowType s
@@ -104,7 +104,7 @@ type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) ::
104104 ':<>: 'ShowType field
105105 )
106106
107− ErrorUnlessJust _ _ 'True
107+ ErrorUnlessTrue _ _ 'True
108108 = ()
109109
110110-- |As 'HasField' but over generic representations as defined by
@@ -112,10 +112,10 @@ type family ErrorUnlessJust (field :: Symbol) (s :: Type) (contains :: Bool) ::
112112class GHasField (field :: Symbol) (f :: Type -> Type) a | field f -> a where
113113 gfield :: Lens' (f x) a
114114
115−instance GProductHasField field l r a (HasFieldP field l)
115+instance GProductHasField field l r a (HasTotalFieldP field l)
116116 => GHasField field (l :*: r) a where
117117
118− gfield = gproductField @field @_ @_ @_ @(HasFieldP field l)
118+ gfield = gproductField @field @_ @_ @_ @(HasTotalFieldP field l)
119119
120120instance (GHasField field l a, GHasField field r a)
121121 => GHasField field (l :+: r) a where
src/Data/Generics/Product/Positions.hs+1−1
@@ -36,7 +36,7 @@ module Data.Generics.Product.Positions
3636
3737import Data.Generics.Internal.Lens
3838
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
4040import GHC.Generics
4141import GHC.TypeLits
4242
src/Data/Generics/Product/Typed.hs+3−3
@@ -36,7 +36,7 @@ module Data.Generics.Product.Typed
3636import Data.Generics.Internal.Families
3737import Data.Generics.Internal.Lens
3838
39−import Data.Kind (Constraint, Type)
39+import Data.Kind
4040import GHC.Generics
4141import GHC.TypeLits
4242
@@ -113,10 +113,10 @@ type family ErrorUnlessOne (a :: Type) (s :: Type) (count :: Count) :: Constrain
113113class GHasType (f :: Type -> Type) a where
114114 gtyped :: Lens' (f x) a
115115
116−instance GProductHasType l r a (HasTypeP a l)
116+instance GProductHasType l r a (HasTotalTypeP a l)
117117 => GHasType (l :*: r) a where
118118
119− gtyped = gproductTyped @_ @_ @_ @(HasTypeP a l)
119+ gtyped = gproductTyped @_ @_ @_ @(HasTotalTypeP a l)
120120
121121instance (GHasType l a, GHasType r a) => GHasType (l :+: r) a where
122122 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