@@ -0,0 +1,215 @@
1+{-# language AllowAmbiguousTypes #-}
2+{-# language DataKinds #-}
3+{-# language FlexibleInstances #-}
4+{-# language LambdaCase #-}
5+{-# language MultiParamTypeClasses #-}
6+{-# language RankNTypes #-}
7+{-# language ScopedTypeVariables #-}
8+{-# language StandaloneKindSignatures #-}
9+{-# language TypeApplications #-}
10+{-# language TypeFamilies #-}
11+{-# language TypeOperators #-}
12+{-# language UndecidableInstances #-}
14+module Rel8.Generic.Table.ADT
15+ ( GADTTable (fromGADTColumns, toGADTColumns)
21+import Data.Kind ( Constraint, Type )
22+import Data.Proxy ( Proxy( Proxy ) )
24+ ( (:+:)( L1, R1 ), M1( M1 ), U1( U1 )
28+import GHC.TypeLits ( KnownSymbol, symbolVal )
29+import Prelude hiding ( null )
32+import Rel8.FCF ( Eval, Exp )
33+import Rel8.Generic.Table ( GTable, GColumns, fromGColumns, toGColumns )
34+import Rel8.Schema.Context ( Col( Result ) )
35+import Rel8.Schema.Context.Label ( labeler, unlabeler )
36+import Rel8.Schema.HTable ( HTable )
37+import Rel8.Schema.HTable.Label ( HLabel, hlabel, hunlabel )
38+import Rel8.Schema.HTable.Nullify ( HNullify, hnulls, hnullify, hunnullify )
39+import Rel8.Schema.HTable.Product ( HProduct( HProduct ) )
40+import Rel8.Schema.HTable.Type ( HType( HType ) )
41+import qualified Rel8.Schema.Kind as K
42+import Rel8.Schema.Result ( Result )
43+import Rel8.Table ( null, nullifier, unnullifier )
44+import Rel8.Type.Tag ( Tag( Tag ) )
47+import Data.Text ( pack )
51+ :: (Type -> Exp K.HTable)
52+ -> (Type -> Type) -> K.HTable
53+type family GADTColumns _Columns rep where
54+ GADTColumns _Columns (M1 D _ rep) =
55+ GADTColumns' _Columns (HLabel "tag" (HType Tag)) rep
59+ :: (Type -> Exp K.HTable)
60+ -> K.HTable -> (Type -> Type) -> K.HTable
61+type family GADTColumns' _Columns htable rep where
62+ GADTColumns' _Columns htable (a :+: b) =
63+ GADTColumns' _Columns (GADTColumns' _Columns htable a) b
64+ GADTColumns' _Columns htable (M1 C ('MetaCons _ _ _) U1) = htable
65+ GADTColumns' _Columns htable (M1 C ('MetaCons label _ _) rep) =
66+ HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
70+ :: (Type -> Exp Constraint)
71+ -> (Type -> Exp K.HTable)
72+ -> (Type -> Type) -> Constraint
73+class GADTTable _Table _Columns rep where
74+ fromGADTColumns :: ()
75+ => (forall a. Eval (_Table a) => Eval (_Columns a) (Col Result) -> a)
76+ -> GADTColumns _Columns rep (Col Result)
80+ => (forall a. Eval (_Table a) => a -> Eval (_Columns a) (Col Result))
82+ -> GADTColumns _Columns rep (Col Result)
86+ ( htable ~ HLabel "tag" (HType Tag)
87+ , GADTTable' _Table _Columns htable rep
89+ => GADTTable _Table _Columns (M1 D meta rep)
91+ fromGADTColumns fromColumns columns =
92+ case fromGADTColumns' @_Table @_Columns fromColumns tag columns of
94+ _ -> error "ADT.fromColumns: mismatch between tag and data"
96+ tag = (\(HType (Result a)) -> a) . hunlabel @_ @"tag" unlabeler
98+ toGADTColumns toColumns (M1 rep) =
99+ toGADTColumns' @_Table @_Columns toColumns tag (Just rep)
101+ tag = hlabel @_ @"tag" labeler . HType . Result
105+ :: (Type -> Exp Constraint)
106+ -> (Type -> Exp K.HTable)
107+ -> K.HTable -> (Type -> Type) -> Constraint
108+class GADTTable' _Table _Columns htable rep where
109+ fromGADTColumns' :: ()
110+ => (forall a. Eval (_Table a) => Eval (_Columns a) (Col Result) -> a)
111+ -> (htable (Col Result) -> Tag)
112+ -> GADTColumns' _Columns htable rep (Col Result)
115+ toGADTColumns' :: ()
116+ => (forall a. Eval (_Table a) => a -> Eval (_Columns a) (Col Result))
117+ -> (Tag -> htable (Col Result))
119+ -> GADTColumns' _Columns htable rep (Col Result)
121+ extract :: GADTColumns' _Columns htable rep context -> htable context
125+ ( htable' ~ GADTColumns' _Columns htable a
126+ , GADTTable' _Table _Columns htable a
127+ , GADTTable' _Table _Columns htable' b
129+ => GADTTable' _Table _Columns htable (a :+: b)
131+ fromGADTColumns' fromColumns f columns =
133+ Just a -> Just (L1 a)
135+ fromGADTColumns' @_Table @_Columns @_ @b
137+ (f . extract @_Table @_Columns @_ @a)
141+ fromGADTColumns' @_Table @_Columns @_ @a
144+ (extract @_Table @_Columns @_ @b columns)
146+ toGADTColumns' toColumns tag = \case
148+ toGADTColumns' @_Table @_Columns @_ @b
150+ (\_ -> toGADTColumns' @_Table @_Columns @_ @a
156+ toGADTColumns' @_Table @_Columns @_ @b
159+ toGADTColumns' @_Table @_Columns @_ @a
165+ toGADTColumns' @_Table @_Columns @_ @b
167+ (\_ -> toGADTColumns' @_Table @_Columns @_ @a toColumns tag Nothing)
170+ extract = extract @_Table @_Columns @_ @a . extract @_Table @_Columns @_ @b
173+instance KnownSymbol label =>
174+ GADTTable' _Table _Columns htable (M1 C ('MetaCons label _fixity _isRecord) U1)
176+ fromGADTColumns' _ tag columns
177+ | tag columns == tag' = Just (M1 U1)
178+ | otherwise = Nothing
180+ tag' = Tag $ pack $ symbolVal (Proxy @label)
182+ toGADTColumns' _ tag _ = tag tag'
184+ tag' = Tag $ pack $ symbolVal (Proxy @label)
189+instance {-# OVERLAPPABLE #-}
190+ ( HTable (GColumns _Columns rep)
191+ , GTable _Table _Columns (Col Result) rep
193+ , GADTColumns' _Columns htable (M1 C ('MetaCons label _fixity _isRecord) rep) ~
194+ HProduct htable (HLabel label (HNullify (GColumns _Columns rep)))
196+ => GADTTable' _Table _Columns htable (M1 C ('MetaCons label _fixity _isRecord) rep)
198+ fromGADTColumns' fromColumns tag (HProduct a b)
200+ M1 . fromGColumns @_Table @_Columns fromColumns <$>
201+ hunnullify unnullifier (hunlabel unlabeler b)
202+ | otherwise = Nothing
204+ tag' = Tag $ pack $ symbolVal (Proxy @label)
206+ toGADTColumns' toColumns tag = \case
207+ Nothing -> HProduct (tag tag') (hlabel labeler (hnulls null))
208+ Just (M1 rep) -> HProduct (tag tag') $
210+ hnullify nullifier $
211+ toGColumns @_Table @_Columns toColumns rep
213+ tag' = Tag $ pack $ symbolVal (Proxy @label)
215+ extract (HProduct a _) = a