@@ -0,0 +1,355 @@
1+{-# language AllowAmbiguousTypes #-}
2+{-# language BlockArguments #-}
3+{-# language DataKinds #-}
4+{-# language FlexibleInstances #-}
5+{-# language MultiParamTypeClasses #-}
6+{-# language RankNTypes #-}
7+{-# language ScopedTypeVariables #-}
8+{-# language StandaloneKindSignatures #-}
9+{-# language TupleSections #-}
10+{-# language TypeApplications #-}
11+{-# language TypeFamilies #-}
12+{-# language TypeOperators #-}
13+{-# language UndecidableInstances #-}
15+module Rel8.Generic.Construction.ADT
17+ , GBuildADT, gbuildADT, gunbuildADT
18+ , GConstructADT, gconstructADT, gdeconstructADT
19+ , GFields, CorepFields, gftabulate, gfindex
20+ , GConstructors, CorepConstructors, gctabulate, gcindex
25+import Data.Bifunctor ( first )
26+import Data.Functor.Identity ( runIdentity )
27+import Data.Kind ( Constraint, Type )
28+import Data.List.NonEmpty ( NonEmpty )
29+import Data.Proxy ( Proxy( Proxy ) )
31+ ( (:+:), (:*:)( (:*:) ), M1, U1
35+import GHC.TypeLits ( KnownSymbol, symbolVal )
36+import Prelude hiding ( null )
39+import Rel8.FCF ( Exp )
40+import Rel8.Generic.Construction.Record
41+ ( GConstruct, GConstructable, gconstruct, gdeconstruct
42+ , GFields, Corep, gtabulate, gindex
43+ , FromColumns, ToColumns
45+import Rel8.Generic.Table.ADT ( GColumnsADT, GColumnsADT' )
46+import Rel8.Generic.Table.Record ( GColumns )
47+import Rel8.Schema.Context.Label ( HLabelable, hlabeler, hunlabeler )
48+import Rel8.Schema.HTable ( HTable )
49+import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
50+import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
51+import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
52+import Rel8.Schema.HTable.Type ( HType )
53+import Rel8.Schema.Null ( Nullify )
54+import Rel8.Schema.Spec ( Spec( Spec ), SSpec )
55+import qualified Rel8.Schema.Kind as K
56+import Rel8.Type.Tag ( Tag( Tag ) )
59+import Data.Text ( pack )
62+type Null :: K.HContext -> Type
63+type Null context = forall labels necessity a. ()
64+ => SSpec ('Spec labels necessity a)
65+ -> context ('Spec labels necessity (Nullify a))
68+type Nullifier :: K.HContext -> Type
69+type Nullifier context = forall labels necessity a. ()
70+ => SSpec ('Spec labels necessity a)
71+ -> context ('Spec labels necessity a)
72+ -> context ('Spec labels necessity (Nullify a))
75+type Unnullifier :: K.HContext -> Type
76+type Unnullifier context = forall labels necessity a. ()
77+ => SSpec ('Spec labels necessity a)
78+ -> context ('Spec labels necessity (Nullify a))
79+ -> context ('Spec labels necessity a)
83+ :: (Type -> Exp Type)
84+ -> (Type -> Type) -> Type -> Type -> Type
85+type family GConstructADT f rep r x where
86+ GConstructADT f (M1 D _ rep) r x = GConstructADT f rep r x
87+ GConstructADT f (a :+: b) r x = GConstructADT f a r (GConstructADT f b r x)
88+ GConstructADT f (M1 C _ rep) r x = GConstruct f rep r -> x
91+type GConstructors :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type
92+type family GConstructors f rep where
93+ GConstructors f (M1 D _ rep) = GConstructors f rep
94+ GConstructors f (a :+: b) = GConstructors f a :*: GConstructors f b
95+ GConstructors f (M1 C _ rep) = (->) (GFields f rep)
98+type CorepConstructors :: (Type -> Exp Type) -> (Type -> Type) -> Constraint
99+class CorepConstructors f rep where
100+ gctabulate :: (GConstructors f rep r -> a) -> GConstructADT f rep r a
101+ gcindex :: GConstructADT f rep r a -> GConstructors f rep r -> a
104+instance CorepConstructors f rep => CorepConstructors f (M1 D meta rep) where
105+ gctabulate = gctabulate @f @rep
106+ gcindex = gcindex @f @rep
109+instance (CorepConstructors f a, CorepConstructors f b) =>
110+ CorepConstructors f (a :+: b)
113+ gctabulate @f @a \a -> gctabulate @f @b \b -> f (a :*: b)
114+ gcindex f (a :*: b) = gcindex @f @b (gcindex @f @a f a) b
117+instance Corep f rep => CorepConstructors f (M1 C meta rep) where
118+ gctabulate f = f . gindex @f @rep
119+ gcindex f = f . gtabulate @f @rep
122+type GBuildADT :: (Type -> Exp Type) -> (Type -> Type) -> Type -> Type
123+type family GBuildADT f rep r where
124+ GBuildADT f (M1 D _ rep) r = GBuildADT f rep r
125+ GBuildADT f (a :+: b) r = GBuildADT f a (GBuildADT f b r)
126+ GBuildADT f (M1 C _ rep) r = GConstruct f rep r
129+type GFieldsADT :: (Type -> Exp Type) -> (Type -> Type) -> Type
130+type family GFieldsADT f rep where
131+ GFieldsADT f (M1 D _ rep) = GFieldsADT f rep
132+ GFieldsADT f (a :+: b) = (GFieldsADT f a, GFieldsADT f b)
133+ GFieldsADT f (M1 C _ rep) = GFields f rep
136+type CorepFields :: (Type -> Exp Type) -> (Type -> Type) -> Constraint
137+class CorepFields f rep where
138+ gftabulate :: (GFieldsADT f rep -> a) -> GBuildADT f rep a
139+ gfindex :: GBuildADT f rep a -> GFieldsADT f rep -> a
142+instance CorepFields f rep => CorepFields f (M1 D meta rep) where
143+ gftabulate = gftabulate @f @rep
144+ gfindex = gfindex @f @rep
147+instance (CorepFields f a, CorepFields f b) => CorepFields f (a :+: b)
150+ gftabulate @f @a \a -> gftabulate @f @b \b -> f (a, b)
151+ gfindex f (a, b) = gfindex @f @b (gfindex @f @a f a) b
154+instance Corep f rep => CorepFields f (M1 C meta rep) where
155+ gftabulate = gtabulate @f @rep
156+ gfindex = gindex @f @rep
159+type GConstructableADT
160+ :: (Type -> Exp Constraint)
161+ -> (Type -> Exp K.HTable)
162+ -> (Type -> Exp Type)
163+ -> K.HContext -> (Type -> Type) -> Constraint
164+class GConstructableADT _Table _Columns f context rep where
166+ => ToColumns _Table _Columns f context
167+ -> (Tag -> Nullifier context)
168+ -> HType Tag context
170+ -> GColumnsADT _Columns rep context
173+ => FromColumns _Table _Columns f context
174+ -> (Tag -> Unnullifier context)
175+ -> GColumnsADT _Columns rep context
176+ -> (HType Tag context, GFieldsADT f rep)
179+ => ToColumns _Table _Columns f context
181+ -> Nullifier context
182+ -> (Tag -> HType Tag context)
183+ -> GConstructors f rep (GColumnsADT _Columns rep context)
185+ gdeconstructADT :: ()
186+ => FromColumns _Table _Columns f context
187+ -> (Tag -> Unnullifier context)
188+ -> GConstructors f rep r
189+ -> GColumnsADT _Columns rep context
190+ -> (HType Tag context, NonEmpty (Tag, r))
194+ ( htable ~ HLabel "tag" (HType Tag)
195+ , GConstructableADT' _Table _Columns f context htable rep
196+ , HLabelable context
198+ => GConstructableADT _Table _Columns f context (M1 D meta rep)
200+ gbuildADT toColumns nullifier =
201+ gbuildADT' @_Table @_Columns @f @context @htable @rep toColumns nullifier .
204+ gunbuildADT fromColumns unnullifier =
205+ first (hunlabel hunlabeler) .
206+ gunbuildADT' @_Table @_Columns @f @context @htable @rep fromColumns unnullifier
208+ gconstructADT toColumns null nullifier mk =
209+ gconstructADT' @_Table @_Columns @f @context @htable @rep toColumns null nullifier
210+ (hlabel hlabeler . mk)
212+ gdeconstructADT fromColumns unnullifier cases =
213+ first (hunlabel hunlabeler) .
214+ gdeconstructADT' @_Table @_Columns @f @context @htable @rep fromColumns unnullifier cases
217+type GConstructableADT'
218+ :: (Type -> Exp Constraint)
219+ -> (Type -> Exp K.HTable)
220+ -> (Type -> Exp Type)
221+ -> K.HContext -> K.HTable -> (Type -> Type) -> Constraint
222+class GConstructableADT' _Table _Columns f context htable rep where
224+ => ToColumns _Table _Columns f context
225+ -> (Tag -> Nullifier context)
228+ -> GColumnsADT' _Columns htable rep context
231+ => FromColumns _Table _Columns f context
232+ -> (Tag -> Unnullifier context)
233+ -> GColumnsADT' _Columns htable rep context
234+ -> (htable context, GFieldsADT f rep)
236+ gconstructADT' :: ()
237+ => ToColumns _Table _Columns f context
239+ -> Nullifier context
240+ -> (Tag -> htable context)
241+ -> GConstructors f rep (GColumnsADT' _Columns htable rep context)
243+ gdeconstructADT' :: ()
244+ => FromColumns _Table _Columns f context
245+ -> (Tag -> Unnullifier context)
246+ -> GConstructors f rep r
247+ -> GColumnsADT' _Columns htable rep context
248+ -> (htable context, NonEmpty (Tag, r))
253+ -> GColumnsADT' _Columns htable rep context
257+ ( htable' ~ GColumnsADT' _Columns htable a
258+ , Functor (GConstructors f a)
259+ , GConstructableADT' _Table _Columns f context htable a
260+ , GConstructableADT' _Table _Columns f context htable' b
262+ => GConstructableADT' _Table _Columns f context htable (a :+: b)
264+ gbuildADT' toColumns nullifier htable (a, b) =
265+ gbuildADT' @_Table @_Columns @f @context @htable' @b toColumns nullifier
266+ (gbuildADT' @_Table @_Columns @f @context @htable @a toColumns nullifier htable a)
269+ gunbuildADT' fromColumns unnullifier columns =
270+ case gunbuildADT' @_Table @_Columns @f @context @htable' @b fromColumns unnullifier columns of
272+ case gunbuildADT' @_Table @_Columns @f @context @htable @a fromColumns unnullifier htable' of
273+ (htable, a) -> (htable, (a, b))
275+ gconstructADT' toColumns null nullifier mk =
276+ fmap (gfill @_Table @_Columns @f @context @htable' @b null) (gconstructADT' @_Table @_Columns @f @context @htable @a toColumns null nullifier mk) :*:
277+ gconstructADT' @_Table @_Columns @f @context @htable' @b toColumns null nullifier (gfill @_Table @_Columns @f @context @htable @a null . mk)
279+ gdeconstructADT' fromColumns unnullifier (a :*: b) columns =
280+ case gdeconstructADT' @_Table @_Columns @f @context @htable' @b fromColumns unnullifier b columns of
282+ case gdeconstructADT' @_Table @_Columns @f @context @htable @a fromColumns unnullifier a htable' of
283+ (htable, cases') -> (htable, cases' <> cases)
286+ gfill @_Table @_Columns @f @context @htable' @b null .
287+ gfill @_Table @_Columns @f @context @htable @a null
290+instance (meta ~ 'MetaCons label _fixity _isRecord, KnownSymbol label) =>
291+ GConstructableADT' _Table _Columns f context htable (M1 C meta U1)
293+ gbuildADT' _ _ = const
294+ gunbuildADT' _ _ = (, ())
295+ gconstructADT' _ _ _ f _ = f tag
297+ tag = Tag $ pack $ symbolVal (Proxy @label)
298+ gdeconstructADT' _ _ r htable = (htable, pure (tag, r ()))
300+ tag = Tag $ pack $ symbolVal (Proxy @label)
304+instance {-# OVERLAPPABLE #-}
305+ ( HTable (GColumns _Columns rep)
307+ , meta ~ 'MetaCons label _fixity _isRecord
308+ , HLabelable context
309+ , GConstructable _Table _Columns f context rep
310+ , GColumnsADT' _Columns htable (M1 C meta rep) ~
311+ HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
313+ => GConstructableADT' _Table _Columns f context htable (M1 C meta rep)
315+ gbuildADT' toColumns nullifier htable =
318+ hnullify (nullifier tag) .
319+ gconstruct @_Table @_Columns @f @context @rep toColumns
321+ tag = Tag $ pack $ symbolVal (Proxy @label)
323+ gunbuildADT' fromColumns unnullifier (HProduct htable a) =
325+ , gdeconstruct @_Table @_Columns @f @context @rep fromColumns $
327+ hunnullify (\spec -> pure . unnullifier tag spec) $
332+ tag = Tag $ pack $ symbolVal (Proxy @label)
334+ gconstructADT' toColumns _ nullifier mk =
337+ hnullify nullifier .
338+ gconstruct @_Table @_Columns @f @context @rep toColumns
340+ tag = Tag $ pack $ symbolVal (Proxy @label)
343+ gdeconstructADT' fromColumns unnullifier r (HProduct htable columns) =
348+ a = gdeconstruct @_Table @_Columns @f @context @rep fromColumns $
350+ hunnullify (\spec -> pure . unnullifier tag spec) $
353+ tag = Tag $ pack $ symbolVal (Proxy @label)
355+ gfill null htable = HProduct htable (hlabel hlabeler (hnulls null))