karps-0.1.9.0: src/Spark/Core/Internal/Arithmetics.hs
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE TypeFamilies #-}
-- Required by old versions
{-# LANGUAGE FlexibleContexts #-}
module Spark.Core.Internal.Arithmetics(
GeneralizedHomoReturn,
GeneralizedHomo2,
HomoColOp2,
-- | Developer API
performOp,
) where
import Spark.Core.Internal.ColumnFunctions
import Spark.Core.Internal.ColumnStructures
import Spark.Core.Internal.DatasetStructures
import Spark.Core.Internal.FunctionsInternals(projectColFunction2')
import Spark.Core.Internal.Utilities
{-| All the automatic conversions supported when lifting a -}
type family GeneralizedHomoReturn x1 x2 where
GeneralizedHomoReturn (Column ref x1) (Column ref x1) = Column ref x1
GeneralizedHomoReturn (Column ref x1) DynColumn = DynColumn
GeneralizedHomoReturn (Column ref x1) (LocalData x1) = Column ref x1
GeneralizedHomoReturn (Column ref x1) LocalFrame = DynColumn
GeneralizedHomoReturn DynColumn (Column ref x1) = DynColumn
GeneralizedHomoReturn DynColumn DynColumn = DynColumn
GeneralizedHomoReturn DynColumn (LocalData x1) = DynColumn
GeneralizedHomoReturn DynColumn LocalFrame = DynColumn
GeneralizedHomoReturn (LocalData x1) (Column ref x1) = Column ref x1
GeneralizedHomoReturn (LocalData x1) DynColumn = DynColumn
GeneralizedHomoReturn (LocalData x1) (LocalData x1) = LocalData x1
GeneralizedHomoReturn (LocalData x1) LocalFrame = LocalFrame
GeneralizedHomoReturn LocalFrame (Column ref x1) = DynColumn
GeneralizedHomoReturn LocalFrame LocalFrame = LocalFrame
-- The type of an homogeneous operation.
-- TODO it would be nice to enforce this contstraint at the type level,
-- but it is a bit more complex to do.
type HomoColOp2 = UntypedColumnData -> UntypedColumnData -> UntypedColumnData
{-| The class of types that can be lifted to operations onto Karps types.
This is the class for operations on homogeneous types (the inputs and the
output have the same underlying type).
At its core, it takes a broadcasted operation that works on columns, and
makes that operation available on other shapes.
-}
class GeneralizedHomo2 x1 x2 where
_projectHomo :: x1 -> x2 -> HomoColOp2 -> GeneralizedHomoReturn x1 x2
{-| Performs an operation, using a reference operation defined on columns.
-}
performOp :: (GeneralizedHomo2 x1 x2) =>
HomoColOp2 ->
x1 ->
x2 ->
GeneralizedHomoReturn x1 x2
performOp f x1 x2 = _projectHomo x1 x2 f
-- ******* INSTANCES *********
instance GeneralizedHomo2 DynColumn DynColumn where
_projectHomo = _performDynDyn
instance GeneralizedHomo2 (Column ref x) (Column ref x) where
_projectHomo = _performCC
instance GeneralizedHomo2 DynColumn (Column ref x) where
_projectHomo dc1 c2 = _performDynDyn dc1 (untypedCol c2)
instance GeneralizedHomo2 (Column ref x) DynColumn where
_projectHomo c1 = _performDynDyn (untypedCol c1)
instance GeneralizedHomo2 (Column ref x) (LocalData x) where
_projectHomo c1 o2 = _projectHomo c1 (broadcast o2 c1)
instance GeneralizedHomo2 (LocalData x) (Column ref x) where
_projectHomo o1 c2 = _projectHomo (broadcast o1 c2) c2
instance GeneralizedHomo2 (Column ref x) LocalFrame where
_projectHomo c1 o2' = _projectHomo c1 (broadcast' o2' (untypedCol c1))
instance GeneralizedHomo2 LocalFrame (Column ref x) where
_projectHomo o1' c2 = _projectHomo (broadcast' o1' (untypedCol c2)) c2
instance GeneralizedHomo2 LocalFrame LocalFrame where
_projectHomo o1' o2' f =
let f' x y = f <$> x <*> y
in projectColFunction2' f' o1' o2'
_performDynDyn ::
DynColumn -> DynColumn -> HomoColOp2 -> DynColumn
_performDynDyn dc1 dc2 f = do
c1 <- dc1
c2 <- dc2
-- TODO: add type guard
let c = f c1 c2
-- TODO: add dynamic check on the type of the return
return (dropColType c)
_performCC :: (HasCallStack) =>
Column ref x -> Column ref x -> HomoColOp2 -> Column ref x
_performCC c1 c2 f =
let sqlt = colType c1
c = f (iUntypedColData c1) (iUntypedColData c2)
c' = forceRight $ castCol (colRef c1) sqlt (pure c)
in c'
_performCO :: (HasCallStack) =>
Column ref x -> LocalData x -> HomoColOp2 -> Column ref x
_performCO c1 o2 = _performCC c1 (broadcast o2 c1)