{-# LANGUAGE GADTs, KindSignatures, DeriveDataTypeable, FlexibleInstances, ConstraintKinds, PatternGuards, TemplateHaskell #-} module EnvTypes where import Nat import Data.Function (on) import Data.Typeable (Typeable) import Test.QuickCheck import Test.Feat type EqShow a = (Eq a,Show a,Arbitrary a) data Sigma :: (* -> *) -> * where Si :: EqShow a => r a -> Sigma r data Exists :: (* -> *) -> * where Val :: EqShow a => r a -> a -> Exists r type Repr' = Exists Repr type Ty' = Sigma Repr -- Representations of our types. -- Putting Eq and Show here simplifies those instances for Repr a bit data Repr a where Unit :: Repr () Nat :: Repr Nat PInt :: Repr PInt Bool :: Repr Bool List :: EqShow a => Repr a -> Repr [a] Maybe :: EqShow a => Repr a -> Repr (Maybe a) TupTy :: (EqShow a,EqShow b) => Repr a -> Repr b -> Repr (a,b) TyVar :: Repr Int -- ^ Should this contain more information? deriving Typeable -- The more number of units, the more boring this type is to test data URepr = UUnit () () () | UNat | UPInt | UBool () () | UList URepr | UMaybe URepr () | UTupTy URepr URepr () | UTyVar () () () deriving Typeable deriveEnumerable ''URepr toTy :: URepr -> Ty' toTy u = case u of UUnit{} -> Si Unit UNat -> Si Nat UPInt -> Si PInt UBool{} -> Si Bool UList a | Si a' <- toTy a -> Si (List a') UMaybe a _ | Si a' <- toTy a -> Si (Maybe a') UTupTy a b _ | Si a' <- toTy a , Si b' <- toTy b -> Si (TupTy a' b') UTyVar{} -> Si TyVar enumTy' :: Enumerate Ty' enumTy' = fmap toTy enumerate {-# ANN enumTy's "HLint: ignore Use camelCase" #-} enumTy's :: Enumerate [Ty'] enumTy's = fmap (map toTy) enumerate showRepr :: Repr a -> String showRepr r = case r of Unit -> "Unit" Nat -> "Nat" PInt -> "PInt" Bool -> "Bool" List a -> "List " ++ showRepr a Maybe a -> "Maybe " ++ showRepr a TupTy a b -> "TupTy " ++ showRepr a ++ " " ++ showRepr b TyVar -> "TyVar" showRepr' :: Repr' -> String showRepr' (Val r x) = "Val " ++ showRepr r ++ " " ++ show x instance Show Ty' where show (Si r) = case r of Unit -> "()" Nat -> "Nat" PInt -> "Int" Bool -> "Bool" List a -> "[" ++ show (Si a) ++ "]" Maybe a -> "Maybe " ++ show (Si a) TupTy a b -> "(" ++ show (Si a) ++ "," ++ show (Si b) ++ ")" TyVar -> "a" type Con' = Sigma Con data Con a where TT :: Con () Zero :: Con Nat Succ :: Con Nat Pos :: Con PInt Neg :: Con PInt Tru :: Con Bool Fls :: Con Bool Nil :: EqShow a => Repr a -> Con [a] Cons :: Con [a] Jst :: Con (Maybe a) Ntng :: EqShow a => Repr a -> Con (Maybe a) Tup :: Con (a,b) infoCon' :: Con' -> (Int,String) infoCon' c = case c of Si TT -> (0,"()") Si Zero -> (1,"Zero") Si Succ -> (2,"Succ") Si Nil{} -> (3,"Nil") Si Cons -> (4,"Cons") Si Pos -> (5,"Pos") Si Neg -> (6,"Neg") Si Jst -> (7,"Just") Si Ntng{} -> (8,"Nothing") Si Tru -> (9,"True") Si Fls -> (10,"False") Si Tup -> (11,"Tup") instance Eq Con' where (==) = (==) `on` (fst . infoCon') instance Ord Con' where compare = compare `on` (fst . infoCon') instance Show Con' where show = snd . infoCon' instance Show (Exists a) where show (Val _ x) = show x shrinkRepr' :: Repr' -> [Repr'] shrinkRepr' (Val r x) = map (Val r) (shrink x) data Equal :: * -> * -> * where Refl :: Equal a a (==?) :: Repr a -> Repr b -> Maybe (Equal a b) Unit ==? Unit = Just Refl Nat ==? Nat = Just Refl PInt ==? PInt = Just Refl Bool ==? Bool = Just Refl TyVar ==? TyVar = Just Refl Maybe a ==? Maybe b | Just Refl <- a ==? b = Just Refl List a ==? List b | Just Refl <- a ==? b = Just Refl TupTy a u ==? TupTy b v | Just Refl <- a ==? b , Just Refl <- u ==? v = Just Refl _ ==? _ = Nothing instance Eq (Exists Repr) where Val s u == Val t v = case s ==? t of Just Refl -> u == v Nothing -> False