module Language.Haskell.TH.Instances.Internal where
import Language.Haskell.TH
deriveOrd :: Name -> Q Dec
deriveOrd n = do
TyConI (DataD _ _ _ cons _) <- reify n
na <- newName "a"
nb <- newName "b"
ncheck <- newName "check"
nthen <- newName "_then"
ntag <- newName "_tag"
nx <- newName "x"
ny <- newName "y"
checkClauses <- flip mapM cons $ \con -> do
(pat1, names1) <- conToPat con
(pat2, names2) <- conToPat con
return $ Clause [pat1, pat2]
(NormalB $
foldr (\(n1, n2) ->
AppE (AppE (VarE nthen)
(AppE (AppE (VarE 'compare)
(VarE n1))
(VarE n2))))
(ConE 'EQ)
(zip names1 names2))
[]
let lastCheckClause =
if length cons <= 1
then []
else [Clause [VarP nx, VarP ny]
(NormalB (AppE (AppE (VarE 'compare) (VarE nx)) (VarE ny)))
[]]
tagClauses <- flip mapM (zip [0..] cons) $ \(ix, con) -> do
(pat, _) <- conToPat con
return $ Clause [pat]
(NormalB (SigE (LitE (IntegerL ix))
(ConT ''Int)))
[]
return $ InstanceD []
(AppT (ConT ''Ord) (ConT n))
[FunD 'compare [Clause
[VarP na, VarP nb]
(NormalB (AppE (AppE (VarE ncheck)
(VarE na))
(VarE nb)))
[ FunD ncheck (checkClauses ++ lastCheckClause)
, FunD nthen
[ Clause [ConP 'EQ [], VarP nx] (NormalB (VarE nx)) []
, Clause [VarP nx, WildP] (NormalB (VarE nx)) []
]
, FunD ntag tagClauses
]]]
conToPat :: Con -> Q (Pat, [Name])
conToPat (RecC n fs) = conToPat (NormalC n (map (\(_, s, t) -> (s, t)) fs))
conToPat (ForallC _ _ con) = conToPat con
conToPat (NormalC n tys) = do
names <- mapM (\_ -> newName "_x") tys
return (ConP n (map VarP names), names)
conToPat (InfixC _ n _) = do
ln <- newName "_l"
rn <- newName "_r"
return (InfixP (VarP ln) n (VarP rn), [ln, rn])