dataframe-0.3.3.4: src/DataFrame/Internal/Schema.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
module DataFrame.Internal.Schema where
import qualified Data.Map as M
import qualified Data.Proxy as P
import qualified Data.Text as T
import Data.Maybe (isJust)
import Data.Type.Equality (TestEquality (..))
import DataFrame.Internal.Column (Columnable)
import Type.Reflection (typeRep)
-- | A runtime tag for a column’s element type.
data SchemaType where
-- | Constructor carrying a 'Proxy' of the element type.
SType :: (Columnable a) => P.Proxy a -> SchemaType
{- | Show the underlying element type using 'typeRep'.
==== __Examples__
>>> :set -XTypeApplications
>>> show (schemaType @Bool)
"Bool"
-}
instance Show SchemaType where
show :: SchemaType -> String
show (SType (_ :: P.Proxy a)) = show (typeRep @a)
{- | Two 'SchemaType's are equal iff their element types are the same.
==== __Examples__
>>> :set -XTypeApplications
>>> schemaType @Int == schemaType @Int
True
>>> schemaType @Int == schemaType @Integer
False
-}
instance Eq SchemaType where
(==) :: SchemaType -> SchemaType -> Bool
(==) (SType (_ :: P.Proxy a)) (SType (_ :: P.Proxy b)) =
isJust (testEquality (typeRep @a) (typeRep @b))
{- | Construct a 'SchemaType' for the given @a@.
==== __Examples__
>>> :set -XTypeApplications
>>> schemaType @T.Text == schemaType @T.Text
True
>>> show (schemaType @Double)
"Double"
-}
schemaType :: forall a. (Columnable a) => SchemaType
schemaType = SType (P.Proxy @a)
{- | Logical schema of a 'DataFrame': a mapping from column names to their
element types ('SchemaType').
==== __Examples__
Constructing and querying a schema:
>>> import qualified Data.Map as M
>>> import qualified Data.Text as T
>>> let s = Schema (M.fromList [("country", schemaType @T.Text), ("amount", schemaType @Double)])
>>> M.lookup "amount" (elements s) == Just (schemaType @Double)
True
Extending a schema:
>>> let s' = Schema (M.insert "discount" (schemaType @Double) (elements s))
>>> M.member "discount" (elements s')
True
Equality is structural over the map contents:
>>> let a = Schema (M.fromList [("x", schemaType @Int), ("y", schemaType @Double)])
>>> let b = Schema (M.fromList [("y", schemaType @Double), ("x", schemaType @Int)])
>>> a == b
True
-}
newtype Schema = Schema
{ elements :: M.Map T.Text SchemaType
{- ^ Mapping from /column name/ to its 'SchemaType'.
Invariant: keys are unique column names. A missing key means the column
is not present in the schema.
-}
}
deriving (Show, Eq)