{-# LANGUAGE GADTs, ConstraintKinds, ExplicitForAll, PatternGuards #-}
module Env where
import Test.QuickCheck
import Control.Applicative
import Induction.Structural
import EnvTypes
import Nat
import Util
type Oblig = Obligation Con' String Ty'
type Tm = Term Con' String
type P = Predicate Con' String
type Hyp = Hypothesis Con' String Ty'
-- | A small test environment. No exponentials for now.
testEnv :: Repr a -> Maybe [(Con a,[Arg Ty'])]
testEnv t = case t of
Unit -> Just [(TT,[])]
Nat -> Just [(Zero,[])
,(Succ,[Rec (Si Nat)])
]
PInt -> Just [(Pos,[NonRec (Si Nat)])
,(Neg,[NonRec (Si Nat)])
]
Bool -> Just [(Tru,[]),(Fls,[])]
List a -> Just [(Nil a,[])
,(Cons,[NonRec (Si a),Rec (Si (List a))])
]
Maybe a -> Just [(Ntng a,[])
,(Jst,[NonRec (Si a)])
]
TupTy a b -> Just [(Tup,[NonRec (Si a),NonRec (Si b)])]
TyVar -> Nothing
-- | Forgetting some type info
testEnv' :: TyEnv Con' Ty'
testEnv' (Si t) = case testEnv t of
Just ksargs -> Just (map (uncurry forget) ksargs)
Nothing -> Nothing
where
forget :: forall a . EqShow a => Con a -> [Arg Ty'] -> (Con',[Arg Ty'])
forget k args = (Si k, args)
-- | Generates a random value of some type
arbFromType :: Repr a -> Gen a
arbFromType t = case t of
Unit -> arbitrary
Nat -> arbitrary
PInt -> arbitrary
Bool -> arbitrary
List a -> halfSize $ \ s -> frequency
[ (1, return [])
, (s, (:) <$> arbFromType a <*> arbFromType (List a))
]
Maybe a -> sized $ \ s -> frequency
[ (1, return Nothing)
, (s, Just <$> arbFromType a)
]
TupTy a b -> (,) <$> arbFromType a <*> arbFromType b
TyVar -> arbitrary
-- | Forget type information
arbFromType' :: Sigma Repr -> Gen (Exists Repr)
arbFromType' (Si r) = Val r <$> arbFromType r
startFromTypes :: [Ty'] -> Gen [Repr']
startFromTypes = mapM arbFromType'
-- Cannot make this well typed in a nice way
mkCon :: Con' -> [Repr'] -> Repr'
mkCon (Si c) as = case c of
TT -> case as of { [] -> Val Unit () ; _ -> ill_typed }
Zero -> case as of { [] -> Val Nat Z ; _ -> ill_typed }
Succ -> case as of { [Val Nat n] -> Val Nat (S n) ; _ -> ill_typed }
Pos -> case as of { [Val Nat n] -> Val PInt (P n) ; _ -> ill_typed }
Neg -> case as of { [Val Nat n] -> Val PInt (N n) ; _ -> ill_typed }
Fls -> case as of { [] -> Val Bool False ; _ -> ill_typed }
Tru -> case as of { [] -> Val Bool True ; _ -> ill_typed }
Ntng a -> case as of { [] -> Val (Maybe a) Nothing ; _ -> ill_typed }
Jst -> case as of { [Val a x] -> Val (Maybe a) (Just x) ; _ -> ill_typed }
Tup -> case as of { [Val a x,Val b y] -> Val (TupTy a b) (x,y) ; _ -> ill_typed }
Nil a -> case as of { [] -> Val (List a) [] ; _ -> ill_typed }
Cons -> case as of
[Val a x,Val (List b) xs] -> case a ==? b of
Just Refl -> Val (List a) (x:xs)
Nothing -> error $ "mkCon: " ++ show as ++ " is heterogenous!"
_ -> ill_typed
where
ill_typed :: a
ill_typed = error $ "mkCon: illtyped: " ++ show (Si c) ++ " on " ++ show as
type VarMap = [(String,Repr')]
-- | Tries to match a representation to a term, returning bound variables
match :: Repr' -> Tm -> Maybe VarMap
match v tm0 = case tm0 of
Var s -> Just [(s,v)]
Con (Si c) tms -> case (v,c,tms) of
(Val Unit () , TT , []) -> ok
(Val Nat Z , Zero , []) -> ok
(Val Nat (S x) , Succ , [tm]) -> match (Val Nat x) tm
(Val PInt (P x) , Pos , [tm]) -> match (Val Nat x) tm
(Val PInt (N x) , Neg , [tm]) -> match (Val Nat x) tm
(Val Bool True , Tru , []) -> ok
(Val Bool False , Fls , []) -> ok
(Val (Maybe a) Nothing , Ntng b , []) | Just Refl <- a ==? b -> ok
(Val (Maybe a) (Just x) , Jst , [tm]) -> match (Val a x) tm
(Val (List a) [] , Nil b , []) | Just Refl <- a ==? b -> ok
(Val (List a) (x:xs) , Cons , [t1,t2]) ->
match (Val a x) t1 `comb` match (Val (List a) xs) t2
(Val (TupTy a b) (x,y) , Tup , [t1,t2]) ->
match (Val a x) t1 `comb` match (Val b y) t2
_ -> Nothing
Fun{} -> error "match: No support for exponentials!"
where
ok = Just []
comb r s = (++) <$> r <*> s
-- | Show induction schema
showOblig :: [Oblig] -> String
showOblig = unlines . map ((++ ".") . render . linObligation style)
-- | The style for printing
style :: Style Con' String Ty'
style = Style (text . show) text (text . show)