| Safe Haskell | None |
|---|---|
| Language | Haskell2010 |
DataFrame.Internal.Nullable
Description
Nullable-aware binary operations for expressions.
This module provides two type classes, NullableArithOp and NullableCmpOp,
which enable operators like .+, .-, .*, ./, .== etc. to work
transparently across combinations of nullable (Maybe a) and non-nullable
(a) column types.
The partial functional dependencies uniquely determine the result type from the operand types, so GHC infers it without annotations.
The four combinations covered for each class:
(a, a)— non-nullable × non-nullable(Maybe a, a)— nullable × non-nullable(a, Maybe a)— non-nullable × nullable(Maybe a, Maybe a)— both nullable
Usage
-- Mixing nullable and non-nullable columns: F.col @Int "x".+F.col @(Maybe Int) "y" -- :: Expr (Maybe Int) -- Both non-nullable (existing behaviour preserved): F.col @Int "x".+F.col @Int "y" -- :: Expr Int -- Comparison with three-valued logic: F.col @(Maybe Int) "x".==F.col @Int "y" -- :: Expr (Maybe Bool)
Synopsis
- type family BaseType a where ...
- class (Columnable a, Columnable b, Columnable c) => NullableArithOp a b c | a b -> c where
- nullArithOp :: (BaseType a -> BaseType a -> BaseType a) -> a -> b -> c
- class (Columnable a, Columnable b, Columnable e) => NullableCmpOp a b e where
- class (Columnable a, Columnable r, Columnable c) => NullLift1Op a r c where
- applyNull1 :: (BaseType a -> r) -> a -> c
- class (Columnable a, Columnable b, Columnable r, Columnable c) => NullLift2Op a b r c where
- applyNull2 :: (BaseType a -> BaseType b -> r) -> a -> b -> c
- type family NullLift1Result a r where ...
- type family NullLift2Result a b r where ...
- type family NullCmpResult a b where ...
- class Columnable (Promote a b) => NumericWidenOp a b where
- widenArithOp :: NumericWidenOp a b => (Promote a b -> Promote a b -> Promote a b) -> a -> b -> Promote a b
- type WidenResult a b = NullLift2Result a b (Promote (BaseType a) (BaseType b))
- class Columnable (PromoteDiv a b) => DivWidenOp a b where
- divWiden1 :: a -> PromoteDiv a b
- divWiden2 :: b -> PromoteDiv a b
- divArithOp :: DivWidenOp a b => (PromoteDiv a b -> PromoteDiv a b -> PromoteDiv a b) -> a -> b -> PromoteDiv a b
- type WidenResultDiv a b = NullLift2Result a b (PromoteDiv (BaseType a) (BaseType b))
Type family
type family BaseType a where ... Source #
Strip one layer of Maybe.
BaseType (Maybe a) = a BaseType a = a -- for any non-Maybe type
Arithmetic class
class (Columnable a, Columnable b, Columnable c) => NullableArithOp a b c | a b -> c where Source #
Class for arithmetic binary operations that work transparently over nullable and non-nullable column types.
The functional dependency a b -> c ensures GHC can infer the result type c
from the operand types. The OVERLAPPABLE pragma on the non-nullable instance
ensures the more specific (Maybe a, Maybe a) instance wins when both operands
are nullable.
Instances
| (Columnable a, a ~ BaseType a) => NullableArithOp a a a Source # | Non-nullable × Non-nullable: apply directly, no wrapping.
Arithmetic result is |
Defined in DataFrame.Internal.Nullable | |
| (Columnable a, Columnable (Maybe a), a ~ BaseType a) => NullableArithOp a (Maybe a) (Maybe a) Source # | Non-nullable × Nullable: |
Defined in DataFrame.Internal.Nullable | |
| (Columnable a, Columnable (Maybe a)) => NullableArithOp (Maybe a) a (Maybe a) Source # | Nullable × Non-nullable: |
| (Columnable a, Columnable (Maybe a)) => NullableArithOp (Maybe a) (Maybe a) (Maybe a) Source # | Nullable × Nullable: either |
Comparison class
class (Columnable a, Columnable b, Columnable e) => NullableCmpOp a b e where Source #
Class for comparison binary operations that work transparently over nullable and non-nullable column types.
No functional dependency on e: the OVERLAPPING/OVERLAPPABLE pragmas on
instances disambiguate at call sites without a FundDep (which would conflict
when both operands are Maybe). GHC selects the unique most-specific instance
from the concrete operand types.
Instances
| (Columnable a, Columnable Bool, a ~ BaseType a) => NullableCmpOp a a Bool Source # | |
| (Columnable a, Columnable (Maybe a), Columnable (Maybe Bool), a ~ BaseType a) => NullableCmpOp a (Maybe a) (Maybe Bool) Source # | |
| (Columnable a, Columnable (Maybe a), Columnable (Maybe Bool)) => NullableCmpOp (Maybe a) a (Maybe Bool) Source # | |
| (Columnable a, Columnable (Maybe a), Columnable (Maybe Bool)) => NullableCmpOp (Maybe a) (Maybe a) (Maybe Bool) Source # | |
Generalized nullable lift classes
class (Columnable a, Columnable r, Columnable c) => NullLift1Op a r c where Source #
Methods
applyNull1 :: (BaseType a -> r) -> a -> c Source #
Instances
| (Columnable a, Columnable r, a ~ BaseType a) => NullLift1Op a r r Source # | Non-nullable: apply directly. |
Defined in DataFrame.Internal.Nullable Methods applyNull1 :: (BaseType a -> r) -> a -> r Source # | |
| (Columnable a, Columnable r, Columnable (Maybe r)) => NullLift1Op (Maybe a) r (Maybe r) Source # | Nullable: propagate |
Defined in DataFrame.Internal.Nullable | |
class (Columnable a, Columnable b, Columnable r, Columnable c) => NullLift2Op a b r c where Source #
Methods
applyNull2 :: (BaseType a -> BaseType b -> r) -> a -> b -> c Source #
Instances
| (Columnable a, Columnable b, Columnable r, a ~ BaseType a, b ~ BaseType b) => NullLift2Op a b r r Source # | Both non-nullable: apply directly. |
Defined in DataFrame.Internal.Nullable Methods applyNull2 :: (BaseType a -> BaseType b -> r) -> a -> b -> r Source # | |
| (Columnable a, Columnable b, Columnable r, Columnable (Maybe r), a ~ BaseType a) => NullLift2Op a (Maybe b) r (Maybe r) Source # | Right nullable: |
Defined in DataFrame.Internal.Nullable | |
| (Columnable a, Columnable b, Columnable r, Columnable (Maybe r), b ~ BaseType b) => NullLift2Op (Maybe a) b r (Maybe r) Source # | Left nullable: |
Defined in DataFrame.Internal.Nullable | |
| (Columnable a, Columnable b, Columnable r, Columnable (Maybe r)) => NullLift2Op (Maybe a) (Maybe b) r (Maybe r) Source # | Both nullable: either |
Result-type type families (drive inference in nullLift / nullLift2)
type family NullLift1Result a r where ... Source #
Lift a unary function over a column expression, propagating Nothing.
When a is non-nullable the function is applied directly; when a = Maybe x
the function is applied under the Just and Nothing short-circuits.
Use via nullLift.
Compute the result type of a nullable unary lift.
NullLift1Result (Maybe a) r = Maybe r NullLift1Result a r = r -- for any non-Maybe a
Used by nullLift so GHC can infer the return type
without an explicit annotation.
Equations
| NullLift1Result (Maybe a) r = Maybe r | |
| NullLift1Result a r = r |
type family NullLift2Result a b r where ... Source #
Lift a binary function over two column expressions, propagating Nothing.
The four combinations:
(a, b)— both non-nullable: result isr(Maybe a, b)— left nullable: result isMaybe r(a, Maybe b)— right nullable: result isMaybe r(Maybe a, Maybe b)— both nullable: result isMaybe r
Use via nullLift2.
Compute the result type of a nullable binary lift.
NullLift2Result (Maybe a) b r = Maybe r NullLift2Result a (Maybe b) r = Maybe r -- when a is apart from Maybe NullLift2Result a b r = r
Used by nullLift2 so GHC can infer the return type.
Equations
| NullLift2Result (Maybe a) b r = Maybe r | |
| NullLift2Result a (Maybe b) r = Maybe r | |
| NullLift2Result a b r = r |
Result-type type family for comparison operators
type family NullCmpResult a b where ... Source #
Compute the result type of a nullable comparison.
NullCmpResult (Maybe a) b = Maybe Bool NullCmpResult a (Maybe b) = Maybe Bool -- when a is apart from Maybe NullCmpResult a b = Bool
Used by the comparison operators (.==, .<, etc.) so GHC infers the
return type without an explicit annotation.
Equations
| NullCmpResult (Maybe a) b = Maybe Bool | |
| NullCmpResult a (Maybe b) = Maybe Bool | |
| NullCmpResult a b = Bool |
Numeric widening
class Columnable (Promote a b) => NumericWidenOp a b where Source #
Widen two numeric base types to their promoted common type.
When a ~ b the coercions are identity; otherwise one operand is widened
(e.g. Int → Double).
Instances
| NumericWidenOp Double Float Source # | |
| NumericWidenOp Double Int Source # | |
| NumericWidenOp Float Double Source # | |
| NumericWidenOp Float Int Source # | |
| NumericWidenOp Int Double Source # | |
| NumericWidenOp Int Float Source # | |
| Columnable a => NumericWidenOp a a Source # | Same type: identity coercions. |
widenArithOp :: NumericWidenOp a b => (Promote a b -> Promote a b -> Promote a b) -> a -> b -> Promote a b Source #
Apply an arithmetic function after widening both operands to their common type.
type WidenResult a b = NullLift2Result a b (Promote (BaseType a) (BaseType b)) Source #
Result type of a widening binary operator, accounting for nullable wrappers.
Division widening (integral × integral → Double)
class Columnable (PromoteDiv a b) => DivWidenOp a b where Source #
Like NumericWidenOp but uses PromoteDiv: integral×integral → Double.
Floating types still dominate (Double > Float), and any two integral types
(same or mixed) are both widened to Double.
Instances
divArithOp :: DivWidenOp a b => (PromoteDiv a b -> PromoteDiv a b -> PromoteDiv a b) -> a -> b -> PromoteDiv a b Source #
Apply an arithmetic function after widening both operands via PromoteDiv.
type WidenResultDiv a b = NullLift2Result a b (PromoteDiv (BaseType a) (BaseType b)) Source #
Result type of a division-widening binary operator, accounting for nullable wrappers.