{-# 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