module Data.Singletons.CustomStar (
singletonStar,
module Data.Singletons.Prelude.Eq,
module Data.Singletons.Prelude.Bool
) where
import Language.Haskell.TH
import Data.Singletons.Util
import Data.Singletons.Deriving.Ord
import Data.Singletons.Promote
import Data.Singletons.Promote.Monad
import Data.Singletons.Single.Monad
import Data.Singletons.Single.Data
import Data.Singletons.Single
import Data.Singletons.Syntax
import Data.Singletons.Names
import Control.Monad
import Data.Maybe
import Language.Haskell.TH.Desugar
import Data.Singletons.Prelude.Eq
import Data.Singletons.Prelude.Bool
singletonStar :: DsMonad q
=> [Name]
-> q [Dec]
singletonStar names = do
kinds <- mapM getKind names
ctors <- zipWithM (mkCtor True) names kinds
let repDecl = DDataD Data [] repName [] ctors
[''Eq, ''Show, ''Read]
fakeCtors <- zipWithM (mkCtor False) names kinds
let dataDecl = DataDecl Data repName [] fakeCtors [''Show, ''Read , ''Eq]
ordInst <- mkOrdInstance (DConT repName) fakeCtors
(pOrdInst, promDecls) <- promoteM [] $ do promoteDataDec dataDecl
promoteInstanceDec mempty ordInst
singletonDecls <- singDecsM [] $ do decs1 <- singDataD dataDecl
dec2 <- singInstD pOrdInst
return (dec2 : decs1)
return $ decsToTH $ repDecl :
promDecls ++
singletonDecls
where
getKind :: DsMonad q => Name -> q [DKind]
getKind name = do
info <- reifyWithWarning name
dinfo <- dsInfo info
case dinfo of
DTyConI (DDataD _ (_:_) _ _ _ _) _ ->
fail "Cannot make a representation of a constrainted data type"
DTyConI (DDataD _ [] _ tvbs _ _) _ ->
return $ map (fromMaybe DStarK . extractTvbKind) tvbs
DTyConI (DTySynD _ tvbs _) _ ->
return $ map (fromMaybe DStarK . extractTvbKind) tvbs
DPrimTyConI _ n _ ->
return $ replicate n DStarK
_ -> fail $ "Invalid thing for representation: " ++ (show name)
mkCtor :: DsMonad q => Bool -> Name -> [DKind] -> q DCon
mkCtor real name args = do
(types, vars) <- evalForPair $ mapM kindToType args
dataName <- if real then mkDataName (nameBase name) else return name
return $ DCon (map DPlainTV vars) [] dataName $
DNormalC (map (\ty -> (NotStrict, ty)) types)
kindToType :: DsMonad q => DKind -> QWithAux [Name] q DType
kindToType (DForallK _ _) = fail "Explicit forall encountered in kind"
kindToType (DVarK n) = do
addElement n
return $ DVarT n
kindToType (DConK n args) = foldType (DConT n) <$> mapM kindToType args
kindToType (DArrowK k1 k2) = do
t1 <- kindToType k1
t2 <- kindToType k2
return $ DAppT (DAppT DArrowT t1) t2
kindToType DStarK = return $ DConT repName