packages feed

recover-rtti-0.6.0: tests/Test/RecoverRTTI/ConcreteClassifier.hs

module Test.RecoverRTTI.ConcreteClassifier (
    -- * Concrete classifier
    Concrete(..)
  , ConcreteUser(..)
  , Concretes(..)
  ) where

import Data.Kind
import Data.SOP
import Data.SOP.Dict
import Data.Void
import Data.HashMap.Internal.Array qualified as HashMap (Array)
import Data.HashMap.Lazy (HashMap)
import Data.HashSet (HashSet)
import Data.IntMap (IntMap)
import Data.Map (Map)
import Data.Primitive.Array qualified as Prim (Array)
import Data.Ratio
import Data.Sequence (Seq)
import Data.Set (Set)
import Data.Tree (Tree)
import Data.Vector qualified as Vector.Boxed

import Debug.RecoverRTTI

import Test.RecoverRTTI.UserDefined

{-------------------------------------------------------------------------------
  Concrete classifier
-------------------------------------------------------------------------------}

-- | Concrete classifier
--
-- The differences between the \"concrete\" classifier 'Concrete' and the
-- 'Classifier' from the main library are
--
-- * 'Concrete' has explicit cases for user-defined types,
--   whereas `Classifier` merely classifying them as 'UserDefined'`
-- * 'Concrete' does not have any \"deferred\" types
--
-- The constructor names intentionally line up exactly with the main library.
--
-- In "Test.RecoverRRTI.Staged" we show that we can do staged inference,
-- using 'classify' repeatedly to recover /all/ (concrete) type information
-- from the type information returned by 'classify' (/if/ we have full
-- information about which user-defined types we're interested in).
data Concrete (a :: Type) :: Type where
  -- Primitive and user-defined types
  CC_Prim  :: PrimClassifier a -> Concrete a
  CC_Other :: ConcreteUser   a -> Concrete a

  -- Void
  --
  -- We use this when generating elements of empty types
  CC_Void  :: Concrete Void

  -- Compound types with unclassified elements in 'Classifier'
  CC_HashSet      :: Concrete a -> Concrete (HashSet a)
  CC_IntMap       :: Concrete a -> Concrete (IntMap  a)
  CC_Maybe        :: Concrete a -> Concrete (Maybe   a)
  CC_Ratio        :: Concrete a -> Concrete (Ratio   a)
  CC_Set          :: Concrete a -> Concrete (Set     a)
  CC_Tree         :: Concrete a -> Concrete (Tree    a)

  CC_HM_Array     :: Concrete a -> Concrete (HashMap.Array a)
  CC_List         :: Concrete a -> Concrete [a]
  CC_Prim_Array   :: Concrete a -> Concrete (Prim.Array a)
  CC_Sequence     :: Concrete a -> Concrete (Seq a)
  CC_Vector_Boxed :: Concrete a -> Concrete (Vector.Boxed.Vector a)

  CC_Either       :: Concrete a -> Concrete b -> Concrete (Either a b)
  CC_HashMap      :: Concrete a -> Concrete b -> Concrete (HashMap a b)
  CC_Map          :: Concrete a -> Concrete b -> Concrete (Map a b)

  -- Compound types which have classified elements even in 'Classifier'

  CC_Tuple ::
       (SListI xs, IsValidSize (Length xs))
    => Concretes xs -> Concrete (WrappedTuple xs)

newtype Concretes xs = Concretes (NP Concrete xs)

-- | Example user-defined types
data ConcreteUser (a :: Type) where
  CC_Simple   :: ConcreteUser SimpleType
  CC_NonRec   :: Concrete a -> ConcreteUser (NonRecursive a)
  CC_Rec      :: Concrete a -> ConcreteUser (Recursive    a)
  CC_Unlifted :: ConcreteUser ContainsUnlifted

deriving instance Show (Concrete a)
deriving instance Show (ConcreteUser a)

instance SListI xs => Show (Concretes xs) where
  showsPrec p (Concretes xs) =
      case all_NP allShow of
        Dict -> showsPrec p xs
    where
      allShow :: NP (Dict (Compose Show Concrete)) xs
      allShow = hpure Dict