dataframe-1.0.0.1: A fast, safe, and intuitive DataFrame library.
Safe HaskellNone
LanguageHaskell2010

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

type family BaseType a where ... Source #

Strip one layer of Maybe.

BaseType (Maybe a) = a
BaseType a         = a   -- for any non-Maybe type

Equations

BaseType (Maybe a) = a 
BaseType a = a 

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.

Methods

nullArithOp :: (BaseType a -> BaseType a -> BaseType a) -> a -> b -> c Source #

Lift an arithmetic function over the inner (non-Maybe) values. Nothing short-circuits: any Nothing operand produces Nothing.

Instances

Instances details
(Columnable a, a ~ BaseType a) => NullableArithOp a a a Source #

Non-nullable × Non-nullable: apply directly, no wrapping. Arithmetic result is a; comparison result is Bool.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullArithOp :: (BaseType a -> BaseType a -> BaseType a) -> a -> a -> a Source #

(Columnable a, Columnable (Maybe a), a ~ BaseType a) => NullableArithOp a (Maybe a) (Maybe a) Source #

Non-nullable × Nullable: Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullArithOp :: (BaseType a -> BaseType a -> BaseType a) -> a -> Maybe a -> Maybe a Source #

(Columnable a, Columnable (Maybe a)) => NullableArithOp (Maybe a) a (Maybe a) Source #

Nullable × Non-nullable: Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullArithOp :: (BaseType (Maybe a) -> BaseType (Maybe a) -> BaseType (Maybe a)) -> Maybe a -> a -> Maybe a Source #

(Columnable a, Columnable (Maybe a)) => NullableArithOp (Maybe a) (Maybe a) (Maybe a) Source #

Nullable × Nullable: either Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullArithOp :: (BaseType (Maybe a) -> BaseType (Maybe a) -> BaseType (Maybe a)) -> Maybe a -> Maybe a -> Maybe a Source #

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.

Methods

nullCmpOp :: (BaseType a -> BaseType a -> Bool) -> a -> b -> e Source #

Lift a comparison function over the inner values (three-valued logic). Returns Nothing when either operand is Nothing.

Instances

Instances details
(Columnable a, Columnable Bool, a ~ BaseType a) => NullableCmpOp a a Bool Source # 
Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullCmpOp :: (BaseType a -> BaseType a -> Bool) -> a -> a -> Bool Source #

(Columnable a, Columnable (Maybe a), Columnable (Maybe Bool), a ~ BaseType a) => NullableCmpOp a (Maybe a) (Maybe Bool) Source # 
Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullCmpOp :: (BaseType a -> BaseType a -> Bool) -> a -> Maybe a -> Maybe Bool Source #

(Columnable a, Columnable (Maybe a), Columnable (Maybe Bool)) => NullableCmpOp (Maybe a) a (Maybe Bool) Source # 
Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullCmpOp :: (BaseType (Maybe a) -> BaseType (Maybe a) -> Bool) -> Maybe a -> a -> Maybe Bool Source #

(Columnable a, Columnable (Maybe a), Columnable (Maybe Bool)) => NullableCmpOp (Maybe a) (Maybe a) (Maybe Bool) Source # 
Instance details

Defined in DataFrame.Internal.Nullable

Methods

nullCmpOp :: (BaseType (Maybe a) -> BaseType (Maybe a) -> Bool) -> 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

Instances details
(Columnable a, Columnable r, a ~ BaseType a) => NullLift1Op a r r Source #

Non-nullable: apply directly.

Instance details

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 Nothing.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

applyNull1 :: (BaseType (Maybe a) -> r) -> Maybe a -> Maybe r Source #

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

Instances details
(Columnable a, Columnable b, Columnable r, a ~ BaseType a, b ~ BaseType b) => NullLift2Op a b r r Source #

Both non-nullable: apply directly.

Instance details

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: Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

applyNull2 :: (BaseType a -> BaseType (Maybe b) -> r) -> a -> Maybe b -> Maybe r Source #

(Columnable a, Columnable b, Columnable r, Columnable (Maybe r), b ~ BaseType b) => NullLift2Op (Maybe a) b r (Maybe r) Source #

Left nullable: Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

applyNull2 :: (BaseType (Maybe a) -> BaseType b -> r) -> Maybe a -> b -> Maybe r Source #

(Columnable a, Columnable b, Columnable r, Columnable (Maybe r)) => NullLift2Op (Maybe a) (Maybe b) r (Maybe r) Source #

Both nullable: either Nothing short-circuits.

Instance details

Defined in DataFrame.Internal.Nullable

Methods

applyNull2 :: (BaseType (Maybe a) -> BaseType (Maybe b) -> r) -> Maybe a -> Maybe b -> Maybe r Source #

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 is r
  • (Maybe a, b) — left nullable: result is Maybe r
  • (a, Maybe b) — right nullable: result is Maybe r
  • (Maybe a, Maybe b) — both nullable: result is Maybe 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.

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. IntDouble).

Methods

widen1 :: a -> Promote a b Source #

widen2 :: b -> Promote a b Source #

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.

Methods

divWiden1 :: a -> PromoteDiv a b Source #

divWiden2 :: b -> PromoteDiv a b Source #

Instances

Instances details
DivWidenOp Int32 Int32 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int32 Int64 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int32 Double Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int32 Float Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int32 Int Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int64 Int32 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int64 Int64 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int64 Double Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int64 Float Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int64 Int Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Double Int32 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Double Int64 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Double Double Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Double Float Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Double Int Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Float Int32 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Float Int64 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Float Double Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Float Float Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Float Int Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int Int32 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int Int64 Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int Double Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int Float Source # 
Instance details

Defined in DataFrame.Internal.Nullable

DivWidenOp Int Int Source # 
Instance details

Defined in DataFrame.Internal.Nullable

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.