module Data.Singletons.CustomStar ( singletonStar ) where
import Language.Haskell.TH
import Language.Haskell.TH.Syntax ( Quasi(..) )
import Data.Singletons.Util
import Data.Singletons.Promote
import Data.Singletons.Singletons
import Control.Monad
#if __GLASGOW_HASKELL__ >= 707
import Data.Singletons.Decide
import Data.Singletons.Instances
import Data.Singletons.Eq
import Unsafe.Coerce
#endif
singletonStar :: Quasi q
=> [Name]
-> q [Dec]
singletonStar names = do
kinds <- mapM getKind names
ctors <- zipWithM (mkCtor True) names kinds
let repDecl = DataD [] repName [] ctors
[''Eq, ''Show, ''Read]
fakeCtors <- zipWithM (mkCtor False) names kinds
eqInstances <- mkCustomEqInstances fakeCtors
singletonDecls <- singDataD True [] repName [] fakeCtors
[''Show, ''Read
#if __GLASGOW_HASKELL__ < 707
, ''Eq
#endif
]
return $ repDecl :
eqInstances ++
singletonDecls
where
getKind :: Quasi q => Name -> q [Kind]
getKind name = do
info <- reifyWithWarning name
case info of
TyConI (DataD (_:_) _ _ _ _) ->
fail "Cannot make a representation of a constrainted data type"
TyConI (DataD [] _ tvbs _ _) ->
return $ map extractTvbKind tvbs
TyConI (NewtypeD (_:_) _ _ _ _) ->
fail "Cannot make a representation of a constrainted newtype"
TyConI (NewtypeD [] _ tvbs _ _) ->
return $ map extractTvbKind tvbs
TyConI (TySynD _ tvbs _) ->
return $ map extractTvbKind tvbs
PrimTyConI _ n _ ->
return $ replicate n StarT
_ -> fail $ "Invalid thing for representation: " ++ (show name)
mkCtor :: Quasi q => Bool -> Name -> [Kind] -> q Con
mkCtor real name args = do
(types, vars) <- evalForPair $ mapM kindToType args
let ctor = NormalC ((if real then reinterpret else id) name)
(map (\ty -> (NotStrict, ty)) types)
if length vars > 0
then return $ ForallC (map PlainTV vars) [] ctor
else return ctor
kindToType :: Quasi q => Kind -> QWithAux [Name] q Type
kindToType (ForallT _ _ _) = fail "Explicit forall encountered in kind"
kindToType (AppT k1 k2) = do
t1 <- kindToType k1
t2 <- kindToType k2
return $ AppT t1 t2
kindToType (SigT _ _) = fail "Sort signature encountered in kind"
kindToType (VarT n) = do
addElement n
return $ VarT n
kindToType (ConT n) = return $ ConT n
kindToType (PromotedT _) = fail "Promoted type used as a kind"
kindToType (TupleT n) = return $ TupleT n
kindToType (UnboxedTupleT _) = fail "Unboxed tuple kind encountered"
kindToType ArrowT = return ArrowT
kindToType ListT = return ListT
kindToType (PromotedTupleT _) = fail "Promoted tuple kind encountered"
kindToType PromotedNilT = fail "Promoted nil kind encountered"
kindToType PromotedConsT = fail "Promoted cons kind encountered"
kindToType StarT = return $ ConT repName
kindToType ConstraintT =
fail $ "Cannot make a representation of a type that has " ++
"an argument of kind Constraint"
kindToType (LitT _) = fail "Literal encountered at the kind level"
mkCustomEqInstances :: Quasi q => [Con] -> q [Dec]
mkCustomEqInstances ctors = do
#if __GLASGOW_HASKELL__ >= 707
let ctorVar = error "Internal error: Equality instance inspected ctor var"
sCtors <- evalWithoutAux $ mapM (singCtor ctorVar) ctors
decideInst <- mkEqualityInstance StarT sCtors sDecideClassDesc
a <- qNewName "a"
b <- qNewName "b"
let eqInst = InstanceD
[]
(AppT (ConT ''SEq) (kindParam StarT))
[FunD '(%:==)
[Clause [VarP a, VarP b]
(NormalB $
CaseE (foldExp (VarE '(%~)) [VarE a, VarE b])
[ Match (ConP 'Proved [ConP 'Refl []])
(NormalB $ ConE 'STrue) []
, Match (ConP 'Disproved [WildP])
(NormalB $ AppE (VarE 'unsafeCoerce)
(ConE 'SFalse)) []
]) []]]
return [decideInst, eqInst]
#else
mapM mkEqTypeInstance [(c1, c2) | c1 <- ctors, c2 <- ctors]
#endif