module MagicHaskeller.PolyDynamic (
Dynamic(..),
fromDyn,
fromDynamic,
dynApply,
dynApp,
dynAppErr,
unsafeToDyn
, aLittleSafeFromDyn
, fromPD, dynamic,dynamicH
) where
import Data.Typeable
import Data.Maybe
import GHC.Exts(unsafeCoerce#)
import MagicHaskeller.Types
import MagicHaskeller.TyConLib
import Control.Monad
import Language.Haskell.TH hiding (Type)
import Debug.Trace
import MagicHaskeller.ReadTypeRep(trToType)
import MagicHaskeller.ReadTHType(typeToTHType)
import MagicHaskeller.ReadTHType(thTypeToType)
import MagicHaskeller.MHTH
import Data.Typeable(typeOf)
infixl `dynApp`
data Dynamic = Dynamic {dynType::Type, unsafeFromDyn::forall a. a, dynExp::Exp}
unsafeToDyn :: TyConLib -> Type -> a -> Exp -> Dynamic
unsafeToDyn tcl tr a e = Dynamic (unChin tr) (unsafeCoerce# a) e
aLittleSafeFromDyn :: Type -> Dynamic -> a
aLittleSafeFromDyn tr (Dynamic t o _)
= case mgu tr t of
Just _ -> o
Nothing -> error ("aLittleSafeFromDyn: type mismatch between "++show tr++" and "++show t)
fromDyn :: Typeable a => TyConLib -> Dynamic -> a -> a
fromDyn tcl (Dynamic t o _) dflt
= case mgu (trToType tcl (typeOf dflt)) t of
Just _ -> o
Nothing -> dflt
fromDynamic :: MonadPlus m => Type -> Dynamic -> m a
fromDynamic tr (Dynamic t o _) = mgu tr t >> return o
instance Show Dynamic where
showsPrec _ (Dynamic t _ e) = ("<dynamic "++) . (pprint e++) . ("::"++) . showsPrec 0 t . ('>':)
dynApply :: Dynamic -> Dynamic -> Maybe Dynamic
dynApply (Dynamic t1 f e1) (Dynamic t2 x e2) =
case mguFunAp t1 t2 of
Just t3 ->
Just (Dynamic t3 ((unsafeCoerce# f) x) (AppE e1 e2))
Nothing -> Nothing
dynApp :: Dynamic -> Dynamic -> Dynamic
dynApp = dynAppErr ""
dynAppErr :: String ->Dynamic -> Dynamic -> Dynamic
dynAppErr s f x = case dynApply f x of
Just r -> r
Nothing -> error ("Type error in dynamic application.\n" ++
"Can't apply function " ++ show f ++
" to argument " ++ show x ++ "\n" ++ s)
fromPD = id
dynamic :: ExpQ -> ExpQ -> ExpQ
dynamic eqtcl eq = eq >>= p' eqtcl
dynamicH :: ExpQ -> Name -> TypeQ -> ExpQ
dynamicH eqtcl nm tq = do t <- tq
px eqtcl (VarE nm) t
p' eqtcl (SigE e ty) = px eqtcl e ty
p' eqtcl e = [| unsafeToDyn $eqtcl (trToType $eqtcl (typeOf $(return e))) $(return e) $(expToExpExp e) |]
px eqtcl e ty = [| unsafeToDyn $eqtcl (thTypeToType $eqtcl $(typeToExpType ty)) $(return se) $(expToExpExp e) |]
where se = SigE e ty