1{-# language DataKinds #-}
2{-# language DeriveFunctor #-}
3{-# language DerivingStrategies #-}
4{-# language FlexibleContexts #-}
5{-# language FlexibleInstances #-}
6{-# language LambdaCase #-}
7{-# language MultiParamTypeClasses #-}
8{-# language NamedFieldPuns #-}
9{-# language ScopedTypeVariables #-}
10{-# language StandaloneKindSignatures #-}
11{-# language TypeApplications #-}
12{-# language TypeFamilies #-}
13{-# language UndecidableInstances #-}
15{-# options_ghc -fno-warn-orphans #-}
17module Rel8.Table.Either
19 , eitherTable, leftTable, rightTable
20 , isLeftTable, isRightTable
26import Control.Applicative ( liftA2 )
27import Data.Bifunctor ( Bifunctor, bimap )
28import Data.Functor.Identity ( runIdentity )
29import Data.Kind ( Type )
30import Prelude hiding ( undefined )
33import Rel8.Expr ( Expr )
34import Rel8.Expr.Serialize ( litExpr )
35import Rel8.Schema.Context.Label
37 , HLabelable, hlabeler, hunlabeler
39import Rel8.Schema.Context.Nullify
40 ( Nullifiable, ConstrainTag
41 , HNullifiable, HConstrainTag
42 , hencodeTag, hdecodeTag
43 , hnullifier, hunnullifier
45import Rel8.Schema.HTable ( HTable )
46import Rel8.Schema.HTable.Either ( HEitherTable(..) )
47import Rel8.Schema.HTable.Identity ( HIdentity(..) )
48import Rel8.Schema.HTable.Label ( hlabel, hunlabel )
49import Rel8.Schema.HTable.Nullify ( hnullify, hunnullify )
50import Rel8.Schema.Name ( Name )
52 ( Table, Columns, Context, fromColumns, toColumns
55import Rel8.Table.Bool ( bool )
56import Rel8.Table.Eq ( EqTable, eqTable )
57import Rel8.Table.Ord ( OrdTable, ordTable )
58import Rel8.Table.Recontextualize ( Recontextualize )
59import Rel8.Table.Serialize ( FromExprs, ToExprs, fromResult, toResult )
60import Rel8.Table.Tag ( Tag(..), fromExpr, fromName )
61import Rel8.Table.Undefined ( undefined )
62import Rel8.Type.Tag ( EitherTag( IsLeft, IsRight ), isLeft, isRight )
65import Data.Functor.Apply ( Apply, (<.>) )
66import Data.Functor.Bind ( Bind, (>>-) )
69-- | An @EitherTable a b@ is a Rel8 table that contains either the table @a@ or
70-- the table @b@. You can construct an @EitherTable@ using 'leftTable' and
71-- 'rightTable', and eliminate/pattern match using 'eitherTable'.
73-- An @EitherTable@ is operationally the same as Haskell's 'Either' type, but
74-- adapted to work with Rel8.
75type EitherTable :: Type -> Type -> Type
76data EitherTable a b = EitherTable
77 { tag :: Tag "isRight" EitherTag
81 deriving stock Functor
84instance Bifunctor EitherTable where
85 bimap f g (EitherTable tag a b) = EitherTable tag (f a) (g b)
88instance Table Expr a => Apply (EitherTable a) where
89 EitherTable tag l1 f <.> EitherTable tag' l2 a =
90 EitherTable (tag <> tag') (bool l1 l2 (isLeft (expr tag))) (f a)
93instance Table Expr a => Applicative (EitherTable a) where
98instance Table Expr a => Bind (EitherTable a) where
99 EitherTable tag l1 a >>- f = case f a of
100 EitherTable tag' l2 b ->
101 EitherTable (tag <> tag') (bool l1 l2 (isRight (expr tag))) b
104instance Table Expr a => Monad (EitherTable a) where
108instance (Table Expr a, Table Expr b) => Semigroup (EitherTable a b) where
109 a <> b = bool a b (isRightTable a)
113 ( Table context a, Table context b
114 , Labelable context, Nullifiable context, ConstrainTag context EitherTag
116 Table context (EitherTable a b)
118 type Columns (EitherTable a b) = HEitherTable (Columns a) (Columns b)
119 type Context (EitherTable a b) = Context a
121 toColumns = toColumns2 toColumns toColumns
122 fromColumns = fromColumns2 fromColumns fromColumns
123 reify = liftA2 bimap reify reify
124 unreify = liftA2 bimap unreify unreify
128 ( Nullifiable from, Labelable from, ConstrainTag from EitherTag
129 , Nullifiable to, Labelable to, ConstrainTag to EitherTag
130 , Recontextualize from to a1 b1
131 , Recontextualize from to a2 b2
133 => Recontextualize from to (EitherTable a1 a2) (EitherTable b1 b2)
136instance (EqTable a, EqTable b) => EqTable (EitherTable a b) where
137 eqTable = toColumns2 id id (rightTableWith (eqTable @a) (eqTable @b))
140instance (OrdTable a, OrdTable b) => OrdTable (EitherTable a b) where
141 ordTable = toColumns2 id id (rightTableWith (ordTable @a) (ordTable @b))
144type instance FromExprs (EitherTable a b) = Either (FromExprs a) (FromExprs b)
147instance (ToExprs exprs1 a, ToExprs exprs2 b, x ~ EitherTable exprs1 exprs2) =>
148 ToExprs x (Either a b)
151 bimap (fromResult @exprs1) (fromResult @exprs2) .
155 bimap (toResult @exprs1) (toResult @exprs2)
158-- | Test if an 'EitherTable' is a 'leftTable'.
159isLeftTable :: EitherTable a b -> Expr Bool
160isLeftTable = isLeft . expr . tag
163-- | Test if an 'EitherTable' is a 'rightTable'.
164isRightTable :: EitherTable a b -> Expr Bool
165isRightTable = isRight . expr . tag
168-- | Pattern match/eliminate an 'EitherTable', by providing mappings from a
169-- 'leftTable' and 'rightTable'.
170eitherTable :: Table Expr c
171 => (a -> c) -> (b -> c) -> EitherTable a b -> c
172eitherTable f g EitherTable {tag, left, right} =
173 bool (f left) (g right) (isRight (expr tag))
176-- | Construct a left 'EitherTable'. Like 'Left'.
177leftTable :: Table Expr b => a -> EitherTable a b
178leftTable a = EitherTable (fromExpr (litExpr IsLeft)) a undefined
181-- | Construct a right 'EitherTable'. Like 'Right'.
182rightTable :: Table Expr a => b -> EitherTable a b
183rightTable = rightTableWith undefined
186rightTableWith :: a -> b -> EitherTable a b
187rightTableWith = EitherTable (fromExpr (litExpr IsRight))
190-- | Construct a 'EitherTable' in the 'Name' context. This can be useful if you
191-- have a 'EitherTable' that you are storing in a table and need to construct a
195 -- ^ The name of the column to track whether a row is a 'leftTable' or
198 -- ^ Names of the columns in the @a@ table.
200 -- ^ Names of the columns in the @b@ table.
202nameEitherTable = EitherTable . fromName
208 , HConstrainTag context EitherTag
210 , HNullifiable context
215 -> HEitherTable t u context
216toColumns2 f g EitherTable {tag, left, right} = HEitherTable
218 , hleft = hlabel hlabeler $ hnullify (hnullifier tag isLeft) $ f left
219 , hright = hlabel hlabeler $ hnullify (hnullifier tag isRight) $ g right
222 htag = HIdentity (hencodeTag tag)
228 , HConstrainTag context EitherTag
230 , HNullifiable context
234 -> HEitherTable t u context
236fromColumns2 f g HEitherTable {htag, hleft, hright} = EitherTable
238 , left = f $ runIdentity $
239 hunnullify (\a -> pure . hunnullifier a) $
242 , right = g $ runIdentity $
243 hunnullify (\a -> pure . hunnullifier a) $
248 tag = hdecodeTag $ unHIdentity htag
keysesc to close
- j k
- move down, up
- enter
- open
- esc
- back, or up a level
- 1 2 3 4
- readme, files, commits, refs
- /
- filter
- y
- copy the clone command
- c
- compare the chosen commit with another (or shift-click both)
- ?
- show or hide this list