@@ -0,0 +1,205 @@
1+{-# LANGUAGE AllowAmbiguousTypes #-}
2+{-# LANGUAGE DataKinds #-}
3+{-# LANGUAGE FlexibleInstances #-}
4+{-# LANGUAGE FunctionalDependencies #-}
6+{-# LANGUAGE InstanceSigs #-}
7+{-# LANGUAGE PolyKinds #-}
8+{-# LANGUAGE Rank2Types #-}
9+{-# LANGUAGE ScopedTypeVariables #-}
10+{-# LANGUAGE TypeApplications #-}
11+{-# LANGUAGE TypeFamilies #-}
12+{-# LANGUAGE TypeOperators #-}
13+{-# LANGUAGE UndecidableInstances #-}
15+{-# LANGUAGE DeriveGeneric #-}
16+-----------------------------------------------------------------------------
18+-- Module : Data.Generics.Sum.HasConstructor
19+-- Copyright : (C) 2017 Csongor Kiss
21+-- Maintainer : Csongor Kiss <kiss.csongor.kiss@gmail.com>
22+-- Stability : experimental
23+-- Portability : non-portable
25+-- Derive prisms generically
28+-----------------------------------------------------------------------------
30+module Data.Generics.Sum.HasConstructor where
32+import Data.Generics.Internal.Lens
34+import GHC.TypeLits (Symbol, TypeError, ErrorMessage (..))
35+import Data.Kind (Type, Constraint)
38+class HasConstructor (con :: Symbol) a s | s con -> a where
43+ , ErrorUnless (ContainsC con (Rep s)) con s
44+ , GHasConstructor con (Rep s) a
45+ ) => HasConstructor con a s where
46+ is = repIso . gconstruct @con
48+type family ErrorUnless (contains :: Bool) (con :: Symbol) (s :: *) :: Constraint where
49+ ErrorUnless 'False con s
50+ = TypeError ( 'ShowType s
51+ ':<>: 'Text " has no constructor with name "
56+data HList (xs :: [Type]) where
58+ (:>) :: x -> HList xs -> HList (x ': xs)
62+append :: HList xs -> HList ys -> HList (xs ++ ys)
64+append (x :> xs) ys = x :> (xs `append` ys)
66+class AsList (tup :: *) (xs :: [*]) | xs -> tup where
67+ asList :: tup -> HList xs
68+ asTuple :: HList xs -> tup
70+instance AsList a '[a] where
77+instance AsList (a, b) '[a, b] where
81+ asTuple (a :> b :> Nil)
84+instance AsList (a, b, c) '[a, b, c] where
88+ asTuple (a :> b :> c :> Nil)
91+instance AsList (a, b, c, d) '[a, b, c, d] where
93+ = a :> b :> c :> d :> Nil
95+ asTuple (a :> b :> c :> d :> Nil)
98+instance AsList (a, b, c, d, e) '[a, b, c, d, e] where
99+ asList (a, b, c, d, e)
100+ = a :> b :> c :> d :> e :> Nil
102+ asTuple (a :> b :> c :> d :> e :> Nil)
105+instance AsList (a, b, c, d, e, f) '[a, b, c, d, e, f] where
106+ asList (a, b, c, d, e, f)
107+ = a :> b :> c :> d :> e :> f :> Nil
109+ asTuple (a :> b :> c :> d :> e :> f :> Nil)
110+ = (a, b, c, d, e, f)
112+instance AsList (a, b, c, d, e, f, g) '[a, b, c, d, e, f, g] where
113+ asList (a, b, c, d, e, f, g)
114+ = a :> b :> c :> d :> e :> f :> g :> Nil
116+ asTuple (a :> b :> c :> d :> e :> f :> g :> Nil)
117+ = (a, b, c, d, e, f, g)
119+instance AsList (a, b, c, d, e, f, g, h) '[a, b, c, d, e, f, g, h] where
120+ asList (a, b, c, d, e, f, g, h)
121+ = a :> b :> c :> d :> e :> f :> g :> h :> Nil
123+ asTuple (a :> b :> c :> d :> e :> f :> g :> h :> Nil)
124+ = (a, b, c, d, e, f, g, h)
126+type family ((xs :: [k]) ++ (ys :: [k])) :: [k] where
128+ (x ': xs) ++ ys = x ': xs ++ ys
130+class GHasConstructor (con :: Symbol) (s :: Type -> Type) a | con s -> a where
131+ gconstruct :: Prism' (s x) a
133+instance GHasConstructor con s a => GHasConstructor con (M1 D c s) a where
134+ gconstruct = mIso . gconstruct @con
136+instance (GCollect s xs, AsList a xs) => GHasConstructor con (M1 C ('MetaCons con f n) s) a where
137+ gconstruct = prism (M1 . gto . asList) (Right . asTuple @_ @xs . gfrom . unM1)
139+instance (GHasConstructor con s a) => GHasConstructor con (M1 S m s) a where
140+ gconstruct = mIso . gconstruct @con
142+class GHasConstructorSum (con :: Symbol) l r a (p :: Bool) | con l r p -> a where
143+ gconstructSum :: Prism' ((l :+: r) x) a
145+instance GHasConstructor con l a => GHasConstructorSum con l r a 'True where
146+ gconstructSum = left . gconstruct @con
148+instance GHasConstructor con r a => GHasConstructorSum con l r a 'False where
149+ gconstructSum = right . gconstruct @con
151+instance GHasConstructorSum con l r a (ContainsC con l) => GHasConstructor con (l :+: r) a where
152+ gconstruct = gconstructSum @con @l @r @a @(ContainsC con l)
154+class Partition xs ys zs | xs ys -> zs, xs zs -> ys where
155+ partition :: HList zs -> (HList xs, HList ys)
157+instance Partition '[] xs xs where
158+ partition xs = (Nil, xs)
160+instance Partition xs ys zs => Partition (x ': xs) ys (x ': zs) where
161+ partition (x :> xs) = (x :> xs', ys')
162+ where (xs', ys') = partition xs
164+class GCollect (s :: Type -> Type) (xs :: [Type]) | s -> xs where
165+ gfrom :: s x -> HList xs
166+ gto :: HList xs -> s x
168+instance (GCollect a as, GCollect b bs, xs ~ (as ++ bs), Partition as bs xs) => GCollect (a :*: b) xs where
169+ gfrom (a :*: b) = gfrom a `append` gfrom b
170+ gto xs = gto l :*: gto r
171+ where (l, r) = partition @as @bs xs
173+instance GCollect (K1 R a) '[a] where
174+ gfrom (K1 x) = x :> Nil
175+ gto (x :> Nil) = K1 x
177+instance GCollect s a => GCollect (M1 S c s) a where
178+ gfrom (M1 x) = gfrom x
181+instance GCollect s a => GCollect (M1 D c s) a where
182+ gfrom (M1 x) = gfrom x
185+instance GCollect s a => GCollect (M1 C c s) a where
186+ gfrom (M1 x) = gfrom x
189+--------------------------------------------------------------------------------
191+type family ContainsC (cname :: Symbol) f :: Bool where
192+ ContainsC cname (C1 ('MetaCons cname _ _) _)
194+ ContainsC cname (f :+: g)
195+ = ContainsC cname f || ContainsC cname g
196+ ContainsC cname (D1 m f)
201+-- | Type-level alternative
202+type family (a :: Bool) || (b :: Bool) :: Bool where