@@ -23,25 +23,27 @@ module Rel8.Table.Either
26−import Control.Applicative ( liftA2 )
27import Control.Category ( id )
26import Control.Category ( id )
28import Data.Bifunctor ( Bifunctor, bimap )
27import Data.Bifunctor ( Bifunctor, bimap )
29−import Data.Functor.Identity ( runIdentity )
30import Data.Kind ( Type )
28import Data.Kind ( Type )
31import Data.Type.Equality ( apply )
29import Data.Type.Equality ( apply )
32import Prelude hiding ( id, undefined )
30import Prelude hiding ( id, undefined )
33+import Control.Comonad ( extract )
35import Rel8.Aggregate ( Col( A ), Aggregate )
36import Rel8.Aggregate ( Col( A ), Aggregate )
36import Rel8.Expr ( Col( E ), Expr )
37import Rel8.Expr ( Col( E ), Expr )
37import Rel8.Expr.Aggregate ( groupByExpr )
38import Rel8.Expr.Aggregate ( groupByExpr )
38import Rel8.Expr.Serialize ( litExpr )
39import Rel8.Expr.Serialize ( litExpr )
40+import Rel8.Kind.Context ( Reifiable )
41+import Rel8.Schema.Context.Abstract ( Abstract )
39−import Rel8.Schema.Context.Nullify ( Nullifiable, nullifier, unnullifier )
42+import Rel8.Schema.Context.Nullify ( Nullifiable )
40import Rel8.Schema.Dict ( Dict( Dict ) )
43import Rel8.Schema.Dict ( Dict( Dict ) )
41import Rel8.Schema.HTable.Either ( HEitherTable(..) )
44import Rel8.Schema.HTable.Either ( HEitherTable(..) )
42import Rel8.Schema.HTable.Identity ( HIdentity(..) )
45import Rel8.Schema.HTable.Identity ( HIdentity(..) )
43import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
46import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
44−import Rel8.Schema.HTable.Nullify ( hnullify, hunnullify )
45import qualified Rel8.Schema.Kind as K
47import qualified Rel8.Schema.Kind as K
46import Rel8.Schema.Name ( Col( N ), Name )
48import Rel8.Schema.Name ( Col( N ), Name )
47import Rel8.Schema.Spec ( Spec( Spec ) )
49import Rel8.Schema.Spec ( Spec( Spec ) )
@@ -51,6 +53,7 @@ import Rel8.Table
52import Rel8.Table.Bool ( bool )
54import Rel8.Table.Bool ( bool )
53import Rel8.Table.Eq ( EqTable, eqTable )
55import Rel8.Table.Eq ( EqTable, eqTable )
56+import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
54import Rel8.Table.Ord ( OrdTable, ordTable )
57import Rel8.Table.Ord ( OrdTable, ordTable )
55import Rel8.Table.Recontextualize ( Recontextualize )
58import Rel8.Table.Recontextualize ( Recontextualize )
56import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
59import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
@@ -71,19 +74,19 @@ import Data.Functor.Bind ( Bind, (>>-) )
71type EitherTable :: K.Context -> Type -> Type -> Type
74type EitherTable :: K.Context -> Type -> Type -> Type
72data EitherTable context a b = EitherTable
75data EitherTable context a b = EitherTable
73 { tag :: Col context ('Spec EitherTag)
76 { tag :: Col context ('Spec EitherTag)
74− , left :: a
77+ , left :: Nullify context a
75− , right :: b
78+ , right :: Nullify context b
77 deriving stock Functor
80 deriving stock Functor
80−instance Bifunctor (EitherTable context) where
83+instance Nullifiable context => Bifunctor (EitherTable context) where
81− bimap f g (EitherTable tag a b) = EitherTable tag (f a) (g b)
84+ bimap f g (EitherTable tag a b) = EitherTable tag (fmap f a) (fmap g b)
84instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where
87instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where
85 EitherTable (E tag) l1 f <.> EitherTable (E tag') l2 a =
88 EitherTable (E tag) l1 f <.> EitherTable (E tag') l2 a =
86− EitherTable (E (tag <> tag')) (bool l1 l2 (isLeft tag)) (f a)
89+ EitherTable (E (tag <> tag')) (bool l1 l2 (isLeft tag)) (f <.> a)
89instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) where
92instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) where
@@ -92,7 +95,7 @@ instance (context ~ Expr, Table Expr a) => Applicative (EitherTable context a) w
94instance (context ~ Expr, Table Expr a) => Bind (EitherTable context a) where
97instance (context ~ Expr, Table Expr a) => Bind (EitherTable context a) where
95− EitherTable (E tag) l1 a >>- f = case f a of
98+ EitherTable (E tag) l1 a >>- f = case f (extract a) of
96 EitherTable (E tag') l2 b ->
99 EitherTable (E tag') l2 b ->
97 EitherTable (E (tag <> tag')) (bool l1 l2 (isRight tag)) b
100 EitherTable (E (tag <> tag')) (bool l1 l2 (isRight tag)) b
@@ -109,7 +112,7 @@ instance (context ~ Expr, Table Expr a, Table Expr b) =>
111 ( Table context a, Table context b
114 ( Table context a, Table context b
112− , Nullifiable context, context ~ context'
115+ , Reifiable context, Abstract context, context ~ context'
114 => Table context' (EitherTable context a b)
117 => Table context' (EitherTable context a b)
@@ -117,29 +120,28 @@ instance
117 type Context (EitherTable context a b) = Context a
120 type Context (EitherTable context a b) = Context a
119 toColumns EitherTable {tag, left, right} = HEitherTable
122 toColumns EitherTable {tag, left, right} = HEitherTable
120− { htag = hlabel (HType tag)
123+ { htag = hlabel $ HType tag
121− , hleft = hlabel $ hnullify (nullifier tag isLeft) $ toColumns left
124+ , hleft = hlabel $ guard tag (== IsLeft) isLeft $ toColumns left
122− , hright = hlabel $ hnullify (nullifier tag isRight) $ toColumns right
125+ , hright = hlabel $ guard tag (== IsRight) isRight $ toColumns right
125 fromColumns HEitherTable {htag, hleft, hright} = EitherTable
128 fromColumns HEitherTable {htag, hleft, hright} = EitherTable
126− { tag = unHIdentity (hunlabel htag)
129+ { tag = unHIdentity $ hunlabel htag
128− fromColumns $
130+ , left = fromColumns $ hunlabel hleft
130− hunnullify (\spec -> pure . unnullifier spec) $
134− fromColumns $
131+ , right = fromColumns $ hunlabel hright
136− hunnullify (\spec -> pure . unnullifier spec) $
141− reify = liftA2 bimap reify reify
134+ reify proof EitherTable {tag, left, right} = EitherTable
142− unreify = liftA2 bimap unreify unreify
135+ { tag
136+ , left = reify proof left
137+ , right = reify proof right
140+ unreify proof EitherTable {tag, left, right} = EitherTable
142+ , left = unreify proof left
143+ , right = unreify proof right
144 coherence = coherence @context @a
146 coherence = coherence @context @a
145 congruence proof abstract =
147 congruence proof abstract =
@@ -149,8 +151,8 @@ instance
152− ( Nullifiable from, from ~ from'
154+ ( Reifiable from, Abstract from, from ~ from'
153− , Nullifiable to, to ~ to'
155+ , Reifiable to, Abstract to, to ~ to'
154 , Recontextualize from to a1 b1
156 , Recontextualize from to a1 b1
155 , Recontextualize from to a2 b2
157 , Recontextualize from to a2 b2
@@ -162,8 +164,8 @@ instance (EqTable a, EqTable b, context ~ Expr) =>
163 eqTable = HEitherTable
165 eqTable = HEitherTable
164 { htag = hlabel (HType Dict)
166 { htag = hlabel (HType Dict)
165− , hleft = hlabel (hnullify (\_ Dict -> Dict) (eqTable @a))
167+ , hleft = hlabel (eqTable @(Nullify context a))
166− , hright = hlabel (hnullify (\_ Dict -> Dict) (eqTable @b))
168+ , hright = hlabel (eqTable @(Nullify context b))
@@ -172,8 +174,8 @@ instance (OrdTable a, OrdTable b, context ~ Expr) =>
173 ordTable = HEitherTable
175 ordTable = HEitherTable
174 { htag = hlabel (HType Dict)
176 { htag = hlabel (HType Dict)
175− , hleft = hlabel (hnullify (\_ Dict -> Dict) (ordTable @a))
177+ , hleft = hlabel (ordTable @(Nullify context a))
176− , hright = hlabel (hnullify (\_ Dict -> Dict) (ordTable @b))
178+ , hright = hlabel (ordTable @(Nullify context b))
@@ -207,17 +209,17 @@ isRightTable EitherTable {tag = E tag} = isRight tag
207eitherTable :: Table Expr c
209eitherTable :: Table Expr c
208 => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c
210 => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c
209eitherTable f g EitherTable {tag = E tag, left, right} =
211eitherTable f g EitherTable {tag = E tag, left, right} =
210− bool (f left) (g right) (isRight tag)
212+ bool (f (extract left)) (g (extract right)) (isRight tag)
213-- | Construct a left 'EitherTable'. Like 'Left'.
215-- | Construct a left 'EitherTable'. Like 'Left'.
214leftTable :: Table Expr b => a -> EitherTable Expr a b
216leftTable :: Table Expr b => a -> EitherTable Expr a b
215−leftTable a = EitherTable (E (litExpr IsLeft)) a undefined
217+leftTable a = EitherTable (E (litExpr IsLeft)) (pure a) undefined
218-- | Construct a right 'EitherTable'. Like 'Right'.
220-- | Construct a right 'EitherTable'. Like 'Right'.
219rightTable :: Table Expr a => b -> EitherTable Expr a b
221rightTable :: Table Expr a => b -> EitherTable Expr a b
220−rightTable = EitherTable (E (litExpr IsRight)) undefined
222+rightTable = EitherTable (E (litExpr IsRight)) undefined . pure
223-- | Lift a pair of aggregating functions to operate on an 'EitherTable'.
225-- | Lift a pair of aggregating functions to operate on an 'EitherTable'.
@@ -227,8 +229,11 @@ aggregateEitherTable :: ()
227 -> (exprs' -> aggregates')
229 -> (exprs' -> aggregates')
228 -> EitherTable Expr exprs exprs'
230 -> EitherTable Expr exprs exprs'
229 -> EitherTable Aggregate aggregates aggregates'
231 -> EitherTable Aggregate aggregates aggregates'
230−aggregateEitherTable f g (EitherTable (E tag) a b) =
232+aggregateEitherTable f g (EitherTable (E tag) a b) = EitherTable
231− EitherTable (A (groupByExpr tag)) (f a) (g b)
233+ { tag = A (groupByExpr tag)
234+ , left = aggregateNullify f a
235+ , right = aggregateNullify g b
234-- | Construct a 'EitherTable' in the 'Name' context. This can be useful if you
239-- | Construct a 'EitherTable' in the 'Name' context. This can be useful if you
@@ -243,4 +248,4 @@ nameEitherTable
244 -- ^ Names of the columns in the @b@ table.
249 -- ^ Names of the columns in the @b@ table.
245 -> EitherTable Name a b
250 -> EitherTable Name a b
246−nameEitherTable = EitherTable . N
251+nameEitherTable tag left right = EitherTable (N tag) (pure left) (pure right)