module Data.Singletons.Single.Eq where
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Desugar
import Data.Singletons.Util
import Data.Singletons.Names
import Control.Monad
type EqualityClassDesc q = ((DCon, DCon) -> q DClause, Name, Name)
sEqClassDesc, sDecideClassDesc :: DsMonad q => EqualityClassDesc q
sEqClassDesc = (mkEqMethClause, sEqClassName, sEqMethName)
sDecideClassDesc = (mkDecideMethClause, sDecideClassName, sDecideMethName)
mkEqualityInstance :: DsMonad q => DKind -> [DCon]
-> EqualityClassDesc q -> q DDec
mkEqualityInstance k ctors (mkMeth, className, methName) = do
let ctorPairs = [ (c1, c2) | c1 <- ctors, c2 <- ctors ]
methClauses <- if null ctors
then mkEmptyMethClauses
else mapM mkMeth ctorPairs
return $ DInstanceD (map (\kvar -> (DConPr className) `DAppPr` kindParam kvar)
(getKindVars k))
(DAppT (DConT className)
(kindParam k))
[DLetDec $ DFunD methName methClauses]
where getKindVars :: DKind -> [DKind]
getKindVars (DVarK x) = [DVarK x]
getKindVars (DConK _ args) = concatMap getKindVars args
getKindVars DStarK = []
getKindVars (DArrowK arg res) = concatMap getKindVars [arg, res]
getKindVars other =
error ("getKindVars sees an unusual kind: " ++ show other)
mkEmptyMethClauses :: DsMonad q => q [DClause]
mkEmptyMethClauses = do
a <- qNewName "a"
return [DClause [DVarPa a, DWildPa] (DCaseE (DVarE a) emptyMatches)]
mkEqMethClause :: DsMonad q => (DCon, DCon) -> q DClause
mkEqMethClause (c1, c2)
| lname == rname = do
lnames <- replicateM lNumArgs (qNewName "a")
rnames <- replicateM lNumArgs (qNewName "b")
let lpats = map DVarPa lnames
rpats = map DVarPa rnames
lvars = map DVarE lnames
rvars = map DVarE rnames
return $ DClause
[DConPa lname lpats, DConPa rname rpats]
(allExp (zipWith (\l r -> foldExp (DVarE sEqMethName) [l, r])
lvars rvars))
| otherwise =
return $ DClause
[DConPa lname (replicate lNumArgs DWildPa),
DConPa rname (replicate rNumArgs DWildPa)]
(DConE $ singDataConName falseName)
where allExp :: [DExp] -> DExp
allExp [] = DConE $ singDataConName trueName
allExp [one] = one
allExp (h:t) = DAppE (DAppE (DVarE $ singValName andName) h) (allExp t)
(lname, lNumArgs) = extractNameArgs c1
(rname, rNumArgs) = extractNameArgs c2
mkDecideMethClause :: DsMonad q => (DCon, DCon) -> q DClause
mkDecideMethClause (c1, c2)
| lname == rname =
if lNumArgs == 0
then return $ DClause [DConPa lname [], DConPa rname []]
(DAppE (DConE provedName) (DConE reflName))
else do
lnames <- replicateM lNumArgs (qNewName "a")
rnames <- replicateM lNumArgs (qNewName "b")
contra <- qNewName "contra"
let lpats = map DVarPa lnames
rpats = map DVarPa rnames
lvars = map DVarE lnames
rvars = map DVarE rnames
refl <- qNewName "refl"
return $ DClause
[DConPa lname lpats, DConPa rname rpats]
(DCaseE (mkTupleDExp $
zipWith (\l r -> foldExp (DVarE sDecideMethName) [l, r])
lvars rvars)
((DMatch (mkTupleDPat (replicate lNumArgs
(DConPa provedName [DConPa reflName []])))
(DAppE (DConE provedName) (DConE reflName))) :
[DMatch (mkTupleDPat (replicate i DWildPa ++
DConPa disprovedName [DVarPa contra] :
replicate (lNumArgs i 1) DWildPa))
(DAppE (DConE disprovedName)
(DLamE [refl] $
DCaseE (DVarE refl)
[DMatch (DConPa reflName []) $
(DAppE (DVarE contra)
(DConE reflName))]))
| i <- [0..lNumArgs1] ]))
| otherwise = do
x <- qNewName "x"
return $ DClause
[DConPa lname (replicate lNumArgs DWildPa),
DConPa rname (replicate rNumArgs DWildPa)]
(DAppE (DConE disprovedName) (DLamE [x] (DCaseE (DVarE x) emptyMatches)))
where
(lname, lNumArgs) = extractNameArgs c1
(rname, rNumArgs) = extractNameArgs c2