{-# LANGUAGE DataKinds, TypeFamilies, KindSignatures, TemplateHaskell, CPP #-}
module Data.Singletons.CustomStar (
singletonStar,
module Data.Singletons.Prelude.Eq,
module Data.Singletons.Prelude.Bool,
module Data.Singletons.TH
) where
import Language.Haskell.TH
import Data.Singletons.Util
import Data.Singletons.Deriving.Infer
import Data.Singletons.Deriving.Ord
import Data.Singletons.Deriving.Show
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 Data.Singletons.TH
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 [] (Just (DConT typeKindName)) ctors
[DDerivClause Nothing (map DConPr [''Eq, ''Ord, ''Read, ''Show])]
fakeCtors <- zipWithM (mkCtor False) names kinds
let dataDecl = DataDecl repName [] fakeCtors
withLocalDeclarations (decToTH repDecl) $ do
dataDeclEqCxt <- inferConstraints (DConPr ''Eq) (DConT repName) fakeCtors
let dataDeclEqInst = DerivedDecl (Just dataDeclEqCxt) (DConT repName) dataDecl
ordInst <- mkOrdInstance Nothing (DConT repName) dataDecl
showInst <- mkShowInstance Nothing (DConT repName) dataDecl
(pInsts, promDecls) <- promoteM [] $ do promoteDataDec dataDecl
promoteDerivedEqDec dataDeclEqInst
traverse (promoteInstanceDec mempty)
[ordInst, showInst]
singletonDecls <- singDecsM [] $ do decs1 <- singDataD dataDecl
decs2 <- singDerivedEqDecs dataDeclEqInst
decs3 <- traverse singInstD pInsts
return (decs1 ++ decs2 ++ decs3)
return $ decsToTH $ repDecl :
promDecls ++
singletonDecls
where
getKind :: DsMonad q => Name -> q [DKind]
getKind name = do
info <- reifyWithLocals name
dinfo <- dsInfo info
case dinfo of
DTyConI (DDataD _ (_:_) _ _ _ _ _) _ ->
fail "Cannot make a representation of a constrained data type"
DTyConI (DDataD _ [] _ tvbs mk _ _) _ -> do
all_tvbs <- buildDataDTvbs tvbs mk
return $ map (fromMaybe (DConT typeKindName) . extractTvbKind) all_tvbs
DTyConI (DTySynD _ tvbs _) _ ->
return $ map (fromMaybe (DConT typeKindName) . extractTvbKind) tvbs
DPrimTyConI _ n _ ->
return $ replicate n $ DConT typeKindName
_ -> 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 False (map (\ty -> (noBang, ty)) types))
(DConT repName)
where
noBang = Bang NoSourceUnpackedness NoSourceStrictness
kindToType :: DsMonad q => [DType] -> DKind -> QWithAux [Name] q DType
kindToType _ (DForallT _ _ _) = fail "Explicit forall encountered in kind"
kindToType args (DAppT f a) = do
a' <- kindToType [] a
kindToType (a' : args) f
kindToType args (DSigT t k) = do
t' <- kindToType [] t
k' <- kindToType [] k
return $ DSigT t' k' `foldType` args
kindToType args (DVarT n) = do
addElement n
return $ DVarT n `foldType` args
kindToType args (DConT n) = return $ DConT name `foldType` args
where name | isTypeKindName n = repName
| otherwise = n
kindToType args DArrowT = return $ DArrowT `foldType` args
kindToType args k@(DLitT {}) = return $ k `foldType` args
kindToType args DWildCardT = return $ DWildCardT `foldType` args