{-# LANGUAGE TemplateHaskell, CPP #-}
module Data.Express.Express.Derive
( deriveExpress
, deriveExpressCascading
, deriveExpressIfNeeded
)
where
import Data.Express.Core
import Data.Express.Express
import Control.Monad
import Data.Char
import Data.List
import Data.Express.Utils.TH
deriveExpress :: Name -> DecsQ
deriveExpress = deriveWhenNeededOrWarn ''Express reallyDeriveExpress
deriveExpressIfNeeded :: Name -> DecsQ
deriveExpressIfNeeded = deriveWhenNeeded ''Express reallyDeriveExpress
deriveExpressCascading :: Name -> DecsQ
deriveExpressCascading = deriveWhenNeeded ''Express reallyDeriveExpressCascading
reallyDeriveExpress :: Name -> DecsQ
reallyDeriveExpress t = do
isEq <- t `isInstanceOf` ''Eq
isOrd <- t `isInstanceOf` ''Ord
(nt,vs) <- normalizeType t
#if __GLASGOW_HASKELL__ >= 710
cxt <- sequence [ [t| $(conT c) $(return v) |]
#else
cxt <- sequence [ classP c [return v]
#endif
| c <- ''Express:([''Eq | isEq] ++ [''Ord | isOrd])
, v <- vs]
cs <- typeConstructorsArgNames t
asName <- newName "x"
let generalizableExpr = mergeIFns $ foldr1 mergeI
[ do retTypeOf <- lookupValN $ "-" ++ replicate (length ns) '>' ++ ":"
let exprs = [[| expr $(varE n) |] | n <- ns]
let conex = [| $(varE retTypeOf) $(conE c) $(varE asName) |]
let root = [| value $(stringE $ showJustName c) $(conex) |]
let rhs = foldl (\e1 e2 -> [| $e1 :$ $e2 |]) root exprs
[d| instance Express $(return nt) where
expr $(asP asName $ conP c (map varP ns)) = $rhs |]
| (c,ns) <- cs
]
cxt |=>| generalizableExpr
reallyDeriveExpressCascading :: Name -> DecsQ
reallyDeriveExpressCascading = reallyDeriveCascading ''Express reallyDeriveExpress