#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL__ >= 706
#define USE_TYPE_LITS 1
#endif
module Data.Reflection
(
Reifies(..)
, reify
, Given(..)
, give
, int, nat
, Z, D, SD, PD
) where
import Control.Monad
import Data.Functor
import Data.Proxy
#ifdef USE_TYPE_LITS
import GHC.TypeLits
#endif
import Language.Haskell.TH hiding (reify)
#ifdef __HUGS__
import Hugs.IOExts
#else
import Unsafe.Coerce
#endif
class Reifies s a | s -> a where
reflect :: proxy s -> a
newtype Magic a r = Magic (forall (s :: *). Reifies s a => Proxy s -> r)
reify :: forall a r. a -> (forall (s :: *). Reifies s a => Proxy s -> r) -> r
reify a k = unsafeCoerce (Magic k :: Magic a r) (const a) Proxy
class Given a where
given :: a
newtype Gift a r = Gift (Given a => r)
give :: forall a r. a -> (Given a => r) -> r
give a k = unsafeCoerce (Gift k :: Gift a r) a
data Z
data D (n :: *)
data SD (n :: *)
data PD (n :: *)
instance Reifies Z Int where
reflect _ = 0
retagD :: (Proxy n -> a) -> proxy (D n) -> a
retagD f _ = f Proxy
retagSD :: (Proxy n -> a) -> proxy (SD n) -> a
retagSD f _ = f Proxy
retagPD :: (Proxy n -> a) -> proxy (PD n) -> a
retagPD f _ = f Proxy
instance Reifies n Int => Reifies (D n) Int where
reflect = (\n -> n + n) <$> retagD reflect
instance Reifies n Int => Reifies (SD n) Int where
reflect = (\n -> n + n + 1) <$> retagSD reflect
instance Reifies n Int => Reifies (PD n) Int where
reflect = (\n -> n + n 1) <$> retagPD reflect
int :: Int -> TypeQ
int n = case quotRem n 2 of
(0, 0) -> conT ''Z
(q,1) -> conT ''PD `appT` int q
(q, 0) -> conT ''D `appT` int q
(q, 1) -> conT ''SD `appT` int q
_ -> error "ghc is bad at math"
nat :: Int -> TypeQ
nat n
| n >= 0 = int n
| otherwise = error "nat: negative"
#if defined(__GLASGOW_HASKELL__) && __GLASGOW_HASKELL < 704
instance Show (Q a)
instance Eq (Q a)
#endif
instance Num a => Num (Q a) where
(+) = liftM2 (+)
(*) = liftM2 (*)
() = liftM2 ()
negate = fmap negate
abs = fmap abs
signum = fmap signum
fromInteger = return . fromInteger
instance Fractional a => Fractional (Q a) where
(/) = liftM2 (/)
recip = fmap recip
fromRational = return . fromRational
instance Num Type where
#ifdef USE_TYPE_LITS
LitT (NumTyLit a) + LitT (NumTyLit b) = LitT (NumTyLit (a+b))
a + b = AppT (AppT (VarT ''(+)) a) b
LitT (NumTyLit a) * LitT (NumTyLit b) = LitT (NumTyLit (a*b))
a * b = AppT (AppT (VarT ''(*)) a) b
#if MIN_VERSION_base(4,8,0)
a b = AppT (AppT (VarT ''()) a) b
#else
() = error "Type.(-): undefined"
#endif
fromInteger = LitT . NumTyLit
#else
(+) = error "Type.(+): undefined"
(*) = error "Type.(*): undefined"
() = error "Type.(-): undefined"
fromInteger n = case quotRem n 2 of
(0, 0) -> ConT ''Z
(q,1) -> ConT ''PD `AppT` fromInteger q
(q, 0) -> ConT ''D `AppT` fromInteger q
(q, 1) -> ConT ''SD `AppT` fromInteger q
_ -> error "ghc is bad at math"
#endif
abs = error "Type.abs"
signum = error "Type.signum"
onProxyType1 :: (Type -> Type) -> (Exp -> Exp)
onProxyType1 f
(SigE _ ta@(AppT (ConT proxyName) (VarT _)))
| proxyName == ''Proxy = ConE 'Proxy `SigE` (ConT ''Proxy `AppT` f ta)
onProxyType1 f a =
LamE [SigP WildP na] body `AppE` a
where
body = ConE 'Proxy `SigE` (ConT ''Proxy `AppT` f na)
na = VarT (mkName "na")
onProxyType2 :: Name -> (Type -> Type -> Type) -> (Exp -> Exp -> Exp)
onProxyType2 _fName f
(SigE _ (AppT (ConT proxyName) ta))
(SigE _ (AppT (ConT proxyName') tb))
| proxyName == ''Proxy,
proxyName' == ''Proxy = ConE 'Proxy `SigE`
(ConT ''Proxy `AppT` f ta tb)
onProxyType2 fName _f a b = VarE fName `AppE` a `AppE` b
instance Num Exp where
(+) = onProxyType2 'addProxy (+)
(*) = onProxyType2 'mulProxy (*)
() = onProxyType2 'subProxy ()
negate = onProxyType1 negate
abs = onProxyType1 abs
signum = onProxyType1 signum
fromInteger n = ConE 'Proxy `SigE` (ConT ''Proxy `AppT` fromInteger n)
#ifdef USE_TYPE_LITS
addProxy :: Proxy a -> Proxy b -> Proxy (a + b)
addProxy _ _ = Proxy
mulProxy :: Proxy a -> Proxy b -> Proxy (a * b)
mulProxy _ _ = Proxy
#if MIN_VERSION_base(4,8,0)
subProxy :: Proxy a -> Proxy b -> Proxy (a b)
subProxy _ _ = Proxy
#else
subProxy :: Proxy a -> Proxy b -> Proxy c
subProxy _ _ = error "Exp.(-): undefined"
#endif
#else
addProxy :: Proxy a -> Proxy b -> Proxy c
addProxy _ _ = error "Exp.(+): undefined"
mulProxy :: Proxy a -> Proxy b -> Proxy c
mulProxy _ _ = error "Exp.(*): undefined"
subProxy :: Proxy a -> Proxy b -> Proxy c
subProxy _ _ = error "Exp.(-): undefined"
#endif