@@ -23,25 +23,27 @@ module Rel8.Table.Either
2323where
2424
2525-- base
26−import Control.Applicative ( liftA2 )
2726import Control.Category ( id )
2827import Data.Bifunctor ( Bifunctor, bimap )
29−import Data.Functor.Identity ( runIdentity )
3028import Data.Kind ( Type )
3129import Data.Type.Equality ( apply )
3230import Prelude hiding ( id, undefined )
3331
32+-- comonad
33+import Control.Comonad ( extract )
34+
3435-- rel8
3536import Rel8.Aggregate ( Col( A ), Aggregate )
3637import Rel8.Expr ( Col( E ), Expr )
3738import Rel8.Expr.Aggregate ( groupByExpr )
3839import Rel8.Expr.Serialize ( litExpr )
39−import Rel8.Schema.Context.Nullify ( Nullifiable, nullifier, unnullifier )
40+import Rel8.Kind.Context ( Reifiable )
41+import Rel8.Schema.Context.Abstract ( Abstract )
42+import Rel8.Schema.Context.Nullify ( Nullifiable )
4043import Rel8.Schema.Dict ( Dict( Dict ) )
4144import Rel8.Schema.HTable.Either ( HEitherTable(..) )
4245import Rel8.Schema.HTable.Identity ( HIdentity(..) )
4346import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
44−import Rel8.Schema.HTable.Nullify ( hnullify, hunnullify )
4547import qualified Rel8.Schema.Kind as K
4648import Rel8.Schema.Name ( Col( N ), Name )
4749import Rel8.Schema.Spec ( Spec( Spec ) )
@@ -51,6 +53,7 @@ import Rel8.Table
5153 )
5254import Rel8.Table.Bool ( bool )
5355import Rel8.Table.Eq ( EqTable, eqTable )
56+import Rel8.Table.Nullify ( Nullify, aggregateNullify, guard )
5457import Rel8.Table.Ord ( OrdTable, ordTable )
5558import Rel8.Table.Recontextualize ( Recontextualize )
5659import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
@@ -71,19 +74,19 @@ import Data.Functor.Bind ( Bind, (>>-) )
7174type EitherTable :: K.Context -> Type -> Type -> Type
7275data EitherTable context a b = EitherTable
7376 { tag :: Col context ('Spec EitherTag)
74− , left :: a
75− , right :: b
77+ , left :: Nullify context a
78+ , right :: Nullify context b
7679 }
7780 deriving stock Functor
7881
7982
80−instance Bifunctor (EitherTable context) where
81− bimap f g (EitherTable tag a b) = EitherTable tag (f a) (g b)
83+instance Nullifiable context => Bifunctor (EitherTable context) where
84+ bimap f g (EitherTable tag a b) = EitherTable tag (fmap f a) (fmap g b)
8285
8386
8487instance (context ~ Expr, Table Expr a) => Apply (EitherTable context a) where
8588 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)
8790
8891
8992instance (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
9295
9396
9497instance (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
9699 EitherTable (E tag') l2 b ->
97100 EitherTable (E (tag <> tag')) (bool l1 l2 (isRight tag)) b
98101
@@ -109,7 +112,7 @@ instance (context ~ Expr, Table Expr a, Table Expr b) =>
109112
110113instance
111114 ( Table context a, Table context b
112− , Nullifiable context, context ~ context'
115+ , Reifiable context, Abstract context, context ~ context'
113116 )
114117 => Table context' (EitherTable context a b)
115118 where
@@ -117,29 +120,28 @@ instance
117120 type Context (EitherTable context a b) = Context a
118121
119122 toColumns EitherTable {tag, left, right} = HEitherTable
120− { htag = hlabel (HType tag)
121− , hleft = hlabel $ hnullify (nullifier tag isLeft) $ toColumns left
122− , hright = hlabel $ hnullify (nullifier tag isRight) $ toColumns right
123+ { htag = hlabel $ HType tag
124+ , hleft = hlabel $ guard tag (== IsLeft) isLeft $ toColumns left
125+ , hright = hlabel $ guard tag (== IsRight) isRight $ toColumns right
123126 }
124127
125128 fromColumns HEitherTable {htag, hleft, hright} = EitherTable
126− { tag = unHIdentity (hunlabel htag)
127− , left =
128− fromColumns $
129− runIdentity $
130− hunnullify (\spec -> pure . unnullifier spec) $
131− hunlabel
132− hleft
133− , right =
134− fromColumns $
135− runIdentity $
136− hunnullify (\spec -> pure . unnullifier spec) $
137− hunlabel
138− hright
129+ { tag = unHIdentity $ hunlabel htag
130+ , left = fromColumns $ hunlabel hleft
131+ , right = fromColumns $ hunlabel hright
139132 }
140133
141− reify = liftA2 bimap reify reify
142− unreify = liftA2 bimap unreify unreify
134+ reify proof EitherTable {tag, left, right} = EitherTable
135+ { tag
136+ , left = reify proof left
137+ , right = reify proof right
138+ }
139+
140+ unreify proof EitherTable {tag, left, right} = EitherTable
141+ { tag
142+ , left = unreify proof left
143+ , right = unreify proof right
144+ }
143145
144146 coherence = coherence @context @a
145147 congruence proof abstract =
@@ -149,8 +151,8 @@ instance
149151
150152
151153instance
152− ( Nullifiable from, from ~ from'
153− , Nullifiable to, to ~ to'
154+ ( Reifiable from, Abstract from, from ~ from'
155+ , Reifiable to, Abstract to, to ~ to'
154156 , Recontextualize from to a1 b1
155157 , Recontextualize from to a2 b2
156158 )
@@ -162,8 +164,8 @@ instance (EqTable a, EqTable b, context ~ Expr) =>
162164 where
163165 eqTable = HEitherTable
164166 { htag = hlabel (HType Dict)
165− , hleft = hlabel (hnullify (\_ Dict -> Dict) (eqTable @a))
166− , hright = hlabel (hnullify (\_ Dict -> Dict) (eqTable @b))
167+ , hleft = hlabel (eqTable @(Nullify context a))
168+ , hright = hlabel (eqTable @(Nullify context b))
167169 }
168170
169171
@@ -172,8 +174,8 @@ instance (OrdTable a, OrdTable b, context ~ Expr) =>
172174 where
173175 ordTable = HEitherTable
174176 { htag = hlabel (HType Dict)
175− , hleft = hlabel (hnullify (\_ Dict -> Dict) (ordTable @a))
176− , hright = hlabel (hnullify (\_ Dict -> Dict) (ordTable @b))
177+ , hleft = hlabel (ordTable @(Nullify context a))
178+ , hright = hlabel (ordTable @(Nullify context b))
177179 }
178180
179181
@@ -207,17 +209,17 @@ isRightTable EitherTable {tag = E tag} = isRight tag
207209eitherTable :: Table Expr c
208210 => (a -> c) -> (b -> c) -> EitherTable Expr a b -> c
209211eitherTable 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)
211213
212214
213215-- | Construct a left 'EitherTable'. Like 'Left'.
214216leftTable :: 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
216218
217219
218220-- | Construct a right 'EitherTable'. Like 'Right'.
219221rightTable :: Table Expr a => b -> EitherTable Expr a b
220−rightTable = EitherTable (E (litExpr IsRight)) undefined
222+rightTable = EitherTable (E (litExpr IsRight)) undefined . pure
221223
222224
223225-- | Lift a pair of aggregating functions to operate on an 'EitherTable'.
@@ -227,8 +229,11 @@ aggregateEitherTable :: ()
227229 -> (exprs' -> aggregates')
228230 -> EitherTable Expr exprs exprs'
229231 -> EitherTable Aggregate aggregates aggregates'
230−aggregateEitherTable f g (EitherTable (E tag) a b) =
231− EitherTable (A (groupByExpr tag)) (f a) (g b)
232+aggregateEitherTable f g (EitherTable (E tag) a b) = EitherTable
233+ { tag = A (groupByExpr tag)
234+ , left = aggregateNullify f a
235+ , right = aggregateNullify g b
236+ }
232237
233238
234239-- | Construct a 'EitherTable' in the 'Name' context. This can be useful if you
@@ -243,4 +248,4 @@ nameEitherTable
243248 -> b
244249 -- ^ Names of the columns in the @b@ table.
245250 -> EitherTable Name a b
246−nameEitherTable = EitherTable . N
251+nameEitherTable tag left right = EitherTable (N tag) (pure left) (pure right)