sqel-0.0.1.0: lib/Sqel/Sum.hs
module Sqel.Sum where
import Generics.SOP (NP ((:*)))
import Generics.SOP.GGP (GCode, GDatatypeInfoOf)
import Generics.SOP.Type.Metadata (ConstructorInfo (Constructor, Infix, Record), DatatypeInfo (ADT))
import Prelude hiding (sum)
import Sqel.Comp (CompColumn (compColumn), CompName (compName), ConstructorFields, MetaFor, RecordFields)
import Sqel.Data.Dd (
Comp (Prod, Sum),
CompInc (Merge, Nest),
ConCol,
Dd (Dd),
DdInc (DdMerge, DdNest),
DdK (DdK),
DdSort (DdCon, DdSum),
DdStruct (DdComp, DdPrim),
DdType,
ProdType (Con),
ProductField (ProductField),
Struct (Comp, Prim),
)
import Sqel.Data.Mods (pattern NoMods, NoMods)
import Sqel.Data.Sel (
IndexName,
MkTSel (mkTSel),
Sel (SelAuto, SelIndex),
SelPrefix (DefaultPrefix, SelPrefix),
SelW (SelWAuto, SelWIndex),
TSel (TSel),
TypeName,
)
import Sqel.Merge (merge)
import Sqel.Names.Rename (Rename (rename))
import Sqel.Names.Set (SetName)
import Sqel.Prim (IndexColumn, IndexColumnWith, primIndex)
import qualified Sqel.Type as T
import Type.Errors (ErrorMessage (Text))
type family SumFields' (fields :: [ConstructorInfo]) (ass :: [[Type]]) :: [ProductField] where
SumFields' '[] '[] = '[]
SumFields' ('Record name fields : cons) (as : ass) = 'ProductField name (ConCol name 'True (RecordFields fields as) as) : SumFields' cons ass
SumFields' ('Constructor name : cons) (as : ass) = 'ProductField name (ConCol name 'False (ConstructorFields name 0 as) as) : SumFields' cons ass
SumFields' ('Infix conName _ _ : _) _ =
TypeError ("Infix constructor not supported: " <> conName)
type family SumFields (info :: DatatypeInfo) (ass :: [[Type]]) :: [ProductField] where
SumFields ('ADT _ _ cons _) ass = SumFields' cons ass
SumFields info _ =
TypeError ("SumFields:" % info)
class DdType s ~ a => SumWith a isel imods arg s | a isel imods arg -> s where
sumWith :: Dd ('DdK isel imods Int64 'Prim) -> arg -> Dd s
-- TODO b ~ a is not needed here, apparently, but it is for ConColumn. investigate and remove here
instance (
b ~ a,
CompName a ('TSel prefix name),
fields ~ SumFields (GDatatypeInfoOf a) (GCode a),
meta ~ MetaFor "sum type" ('ShowType a) "sum",
CompColumn meta fields a arg s
) => SumWith b isel imods arg ('DdK 'SelAuto NoMods a ('Comp ('TSel prefix name) 'Sum 'Nest ('DdK isel imods Int64 'Prim : s))) where
sumWith index arg =
Dd SelWAuto NoMods (DdComp (compName @a) DdSum DdNest (index :* compColumn @meta @fields @a arg))
class DdType s ~ a => Sum a arg s | a arg -> s where
sum :: arg -> Dd s
-- TODO b ~ a is not needed here, apparently, but it is for ConColumn. investigate and remove here
instance (
b ~ a,
CompName a ('TSel prefix name),
IndexName 'DefaultPrefix name iname,
fields ~ SumFields (GDatatypeInfoOf a) (GCode a),
meta ~ MetaFor "sum type" ('ShowType a) "sum",
CompColumn meta fields a arg s
) => Sum b arg ('DdK 'SelAuto NoMods a ('Comp ('TSel prefix name) 'Sum 'Nest (IndexColumn name : s))) where
sum =
sumWith primIndex
sumAs ::
∀ (name :: Symbol) (a :: Type) (s :: DdK) (arg :: Type) .
Sum a arg s =>
Rename s (SetName s name) =>
arg ->
Dd (SetName s name)
sumAs =
rename . sum @a @_ @s
mergeSum ::
∀ (a :: Type) (s :: DdK) (arg :: Type) .
Sum a arg s =>
arg ->
Dd (T.Merge s)
mergeSum =
merge . sum @a @_ @s
class DdType s ~ a => ConColumn a arg s | a arg -> s where
con :: arg -> Dd s
instance (
a ~ ConCol name record fields as,
MkTSel ('TSel 'DefaultPrefix name),
meta ~ MetaFor "constructor" ('Text name) "con",
CompColumn meta fields a arg s
) => ConColumn a arg ('DdK 'SelAuto NoMods (ConCol name record fields as) ('Comp ('TSel 'DefaultPrefix name) ('Prod ('Con as)) 'Nest s)) where
con arg =
Dd SelWAuto NoMods (DdComp mkTSel DdCon DdNest (compColumn @meta @fields @(ConCol name record fields as) arg))
conAs ::
∀ (name :: Symbol) (a :: Type) (s :: DdK) (arg :: Type) .
ConColumn a arg s =>
Rename s (SetName s name) =>
arg ->
Dd (SetName s name)
conAs =
rename . con @a @_ @s
type family Con1Fields (con :: Type) :: [ProductField] where
Con1Fields (ConCol _ 'True '[f] _) = '[f]
Con1Fields (ConCol name 'False '[ 'ProductField _ a] _) = '[ 'ProductField name a]
class DdType s ~ a => Con1Column a arg s | a arg -> s where
con1 :: arg -> Dd s
instance (
a ~ ConCol name record fields as,
TypeName 'DefaultPrefix name tname,
meta ~ MetaFor "constructor" ('Text name) "con1",
CompColumn meta (Con1Fields a) a arg s
) => Con1Column a arg ('DdK 'SelAuto NoMods (ConCol name record fields as) ('Comp ('TSel 'DefaultPrefix name) ('Prod ('Con as)) 'Merge s)) where
con1 arg =
Dd SelWAuto NoMods (DdComp mkTSel DdCon DdMerge (compColumn @meta @(Con1Fields a) @(ConCol name record fields as) arg))
type family RenameCon1 (name :: Symbol) (a :: Type) :: Type where
RenameCon1 name (ConCol _ record '[ 'ProductField _ a] as) =
ConCol name record '[ 'ProductField name a] as
RenameCon1 _ a =
TypeError ("RenameCon1:" % a)
class DdType s ~ a => Con1AsColumn name a arg s | name a arg -> s where
con1As :: arg -> Dd s
instance (
a ~ ConCol _name record _fields as,
TypeName 'DefaultPrefix name tname,
fields ~ Con1Fields (RenameCon1 name a),
meta ~ MetaFor "constructor" ('Text name) "con1As",
CompColumn meta fields a arg s
) => Con1AsColumn name a arg ('DdK 'SelAuto NoMods a ('Comp ('TSel 'DefaultPrefix name) ('Prod ('Con as)) 'Merge s)) where
con1As arg =
Dd SelWAuto NoMods (DdComp mkTSel DdCon DdMerge (compColumn @meta @fields @a arg))
type SetIndexPrefix :: Symbol -> DdK -> DdK -> Constraint
class SetIndexPrefix prefix s0 s1 | prefix s0 -> s1 where
setIndexPrefix :: Dd s0 -> Dd s1
instance (
IndexName ('SelPrefix prefix) tpe iname
) => SetIndexPrefix prefix ('DdK sel mods a ('Comp tsel 'Sum i ('DdK ('SelIndex oldPrefix tpe) NoMods Int64 'Prim : cons))) ('DdK sel mods a ('Comp tsel 'Sum i (IndexColumnWith ('SelPrefix prefix) tpe : cons))) where
setIndexPrefix (Dd sel mods (DdComp tsel DdSum i (Dd (SelWIndex Proxy) NoMods DdPrim :* cons))) =
Dd sel mods (DdComp tsel DdSum i (Dd (SelWIndex Proxy) NoMods DdPrim :* cons))
setIndexPrefix _ =
error "ghc bug?"
indexPrefix ::
∀ prefix s0 s1 .
SetIndexPrefix prefix s0 s1 =>
Dd s0 ->
Dd s1
indexPrefix =
setIndexPrefix @prefix