dataframe-core-2.6.0.0: src-internal/DataFrame/Internal/Expression/Reflect.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE UndecidableInstances #-}
-- | Class evidence for the supported column types, recovered from 'Typeable'.
module DataFrame.Internal.Expression.Reflect (
Dict (..),
RealUnbox,
numDict,
ordDict,
fracDict,
floatingDict,
realDict,
integralDict,
realUnboxDict,
) where
import Data.Foldable (asum)
import Data.Int (Int16, Int32, Int64, Int8)
import Data.Kind (Constraint, Type)
import qualified Data.Text as T
import Data.Type.Equality (testEquality, (:~:) (Refl))
import qualified Data.Vector.Unboxed as VU
import Data.Word (Word16, Word32, Word64, Word8)
import Type.Reflection (Typeable, typeRep)
-- | A captured class dictionary.
data Dict (c :: Constraint) where
Dict :: (c) => Dict c
-- | 'Real' and 'VU.Unbox' together, for variance, median and similar.
class (Real a, VU.Unbox a) => RealUnbox a
instance (Real a, VU.Unbox a) => RealUnbox a
-- | Evidence for @c a@ when @a@ is the concrete type @b@.
via ::
forall b (c :: Type -> Constraint) a.
(Typeable a, Typeable b, c b) => Maybe (Dict (c a))
via = case testEquality (typeRep @a) (typeRep @b) of
Just Refl -> Just Dict
Nothing -> Nothing
-- | The fixed-width integral types.
ints ::
forall (c :: Type -> Constraint) a.
( Typeable a
, c Int
, c Int8
, c Int16
, c Int32
, c Int64
, c Word
, c Word8
, c Word16
, c Word32
, c Word64
) =>
[Maybe (Dict (c a))]
ints =
[ via @Int @c @a
, via @Int8 @c @a
, via @Int16 @c @a
, via @Int32 @c @a
, via @Int64 @c @a
, via @Word @c @a
, via @Word8 @c @a
, via @Word16 @c @a
, via @Word32 @c @a
, via @Word64 @c @a
]
floats ::
forall (c :: Type -> Constraint) a.
(Typeable a, c Double, c Float) => [Maybe (Dict (c a))]
floats = [via @Double @c @a, via @Float @c @a]
numDict :: forall a. (Typeable a) => Maybe (Dict (Num a))
numDict = asum (ints @Num @a ++ [via @Integer @Num @a] ++ floats @Num @a)
ordDict :: forall a. (Typeable a) => Maybe (Dict (Ord a))
ordDict =
asum
( ints @Ord @a
++ [via @Integer @Ord @a]
++ floats @Ord @a
++ [via @Bool @Ord @a, via @Char @Ord @a, via @T.Text @Ord @a, via @String @Ord @a]
)
fracDict :: forall a. (Typeable a) => Maybe (Dict (Fractional a))
fracDict = asum (floats @Fractional @a)
floatingDict :: forall a. (Typeable a) => Maybe (Dict (Floating a))
floatingDict = asum (floats @Floating @a)
realDict :: forall a. (Typeable a) => Maybe (Dict (Real a))
realDict = asum (ints @Real @a ++ [via @Integer @Real @a] ++ floats @Real @a)
integralDict :: forall a. (Typeable a) => Maybe (Dict (Integral a))
integralDict = asum (ints @Integral @a ++ [via @Integer @Integral @a])
-- | 'Integer' is deliberately absent: it is 'Real' but not 'VU.Unbox'.
realUnboxDict :: forall a. (Typeable a) => Maybe (Dict (RealUnbox a))
realUnboxDict = asum (ints @RealUnbox @a ++ floats @RealUnbox @a)