packages feed

keiki-0.5.0.0: src/Keiki/Internal/SymbolicTypes.hs

{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeApplications #-}

-- | The cycle-free, curated set of concrete types understood by Keiki's
-- symbolic layer. This module deliberately contains no SBV dictionaries:
-- 'Keiki.Core' can use it for validation without importing
-- 'Keiki.Symbolic', while 'Keiki.Symbolic' turns the same constructors into
-- the required dictionaries.
module Keiki.Internal.SymbolicTypes
  ( SymbolicType (..),
    discoverSymbolicType,
    symbolicTypeSupportsEquality,
    symbolicTypeSupportsOrdering,
    symbolicTypeSupportsNumeric,
  )
where

import Data.Int (Int32, Int64)
import Data.Text (Text)
import Data.Time (UTCTime)
import Data.Typeable (Typeable)
import Data.Word (Word16, Word32, Word64, Word8)
import Numeric.Natural (Natural)
import Type.Reflection (eqTypeRep, typeRep, type (:~~:) (HRefl))

-- | Evidence that a type belongs to Keiki's closed symbolic registry.
data SymbolicType r where
  SymbolicBool :: SymbolicType Bool
  SymbolicInt :: SymbolicType Int
  SymbolicInteger :: SymbolicType Integer
  SymbolicNatural :: SymbolicType Natural
  SymbolicText :: SymbolicType Text
  SymbolicUTCTime :: SymbolicType UTCTime
  SymbolicWord64 :: SymbolicType Word64
  SymbolicWord32 :: SymbolicType Word32
  SymbolicWord16 :: SymbolicType Word16
  SymbolicWord8 :: SymbolicType Word8
  SymbolicInt64 :: SymbolicType Int64
  SymbolicInt32 :: SymbolicType Int32

-- | Discover membership in the curated registry without importing SBV.
discoverSymbolicType :: forall r. (Typeable r) => Maybe (SymbolicType r)
discoverSymbolicType
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Bool) = Just SymbolicBool
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Int) = Just SymbolicInt
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Integer) = Just SymbolicInteger
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Natural) = Just SymbolicNatural
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Text) = Just SymbolicText
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @UTCTime) = Just SymbolicUTCTime
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Word64) = Just SymbolicWord64
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Word32) = Just SymbolicWord32
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Word16) = Just SymbolicWord16
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Word8) = Just SymbolicWord8
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Int64) = Just SymbolicInt64
  | Just HRefl <- eqTypeRep (typeRep @r) (typeRep @Int32) = Just SymbolicInt32
  | otherwise = Nothing

-- | Every curated type supports symbolic equality.
symbolicTypeSupportsEquality :: SymbolicType r -> Bool
symbolicTypeSupportsEquality _ = True

-- | Whether the registry supplies symbolic ordering for this type.
symbolicTypeSupportsOrdering :: SymbolicType r -> Bool
symbolicTypeSupportsOrdering SymbolicBool = False
symbolicTypeSupportsOrdering SymbolicText = False
symbolicTypeSupportsOrdering _ = True

-- | Whether the registry supplies symbolic numeric operations for this type.
symbolicTypeSupportsNumeric :: SymbolicType r -> Bool
symbolicTypeSupportsNumeric SymbolicInt = True
symbolicTypeSupportsNumeric SymbolicInteger = True
symbolicTypeSupportsNumeric SymbolicWord64 = True
symbolicTypeSupportsNumeric SymbolicWord32 = True
symbolicTypeSupportsNumeric SymbolicWord16 = True
symbolicTypeSupportsNumeric SymbolicWord8 = True
symbolicTypeSupportsNumeric SymbolicInt64 = True
symbolicTypeSupportsNumeric SymbolicInt32 = True
symbolicTypeSupportsNumeric _ = False