-- -- (c) Susumu Katayama 2009 -- module MagicHaskeller.ReadTypeRep where import Data.Typeable import MagicHaskeller.Types as Types import MagicHaskeller.TyConLib import Data.Array.IArray((!)) import qualified Data.Map(lookup) import qualified Language.Haskell.TH as TH typeToTR :: TyConLib -> Type -> TypeRep typeToTR tcl ty = tyToTR tcl 0 ty tyToTR :: TyConLib -> Kind -> Type -> TypeRep tyToTR _ 0 (TV _) = typeOf 'c' -- めんどくさいのでとりあえずChar tyToTR (_,ar) k (TC tc) | tc >= 0 = mkTyConApp (mkTyCon $ fst ((ar!k) !! tc)) [] | otherwise = error "tyToTR: impossible (tc<0)." tyToTR tcl k (TA a b) = mkAppTy (tyToTR tcl (k+1) a) (tyToTR tcl 0 b) tyToTR tcl 0 (a :-> b) = mkFunTy (tyToTR tcl 0 a) (tyToTR tcl 0 b) -- とりあえずはFakeでないDynamicでのtype checkに使うだけなので,効率は考えなくてよい. -- でもまあ,monomorphic限定ならTypeRepの方が速いみたい(?).ソースを見た感じ,特に,equalityに関しては効率的な実装をやってるみたい. {- -- 間違ってもう一回同じものを作ってしまった.kindに関してはtcIDを使った方がいいかも? typeToTR :: TyConLib -> Type -> TypeRep typeToTR _ (TV _) = typeOf 'c' -- めんどくさいのでとりあえずChar typeToTR (_,ar) (TC tc) | tcid >= 0 = mkTyConApp (mkTyCon $ fst ((ar ! tcKind tc) !! tcid)) [] | otherwise = error "tyToTR: impossible (tcid<0)." where tcid = tcID tc typeToTR tcl (TA f a) = mkAppTy (typeToTR tcl f) (typeToTR tcl a) typeToTR tcl (a :-> r) = mkFunTy (typeToTR tcl a) (typeToTR tcl r) -} trToType :: TyConLib -> TypeRep -> Types.Type trToType tcl tr = case splitTyConApp tr of (tc,trs) -> (if tc == funTyCon || show tc == show funTyCon -- dunno why, but sometimes |tc==funTyCon| is not enough. then trToType tcl (head trs) :-> trToType tcl (head (tail trs)) else foldl TA (TC $ fromJust $ Data.Map.lookup (tyConString' tc) (fst tcl)) (map (trToType tcl) trs)) where fromJust (Just x) = x fromJust Nothing = error (tyConString' tc ++ " does not appear in the component library. (This is a known bug.) For now, please use a type variable instead of "++show tc ++ " and use `matching :: Int -> Memo -> TH.Type -> [[TH.Exp]]'.\n(or maybe you forgot to set a component library?)") -- fromJust Nothing = error ("tyConString = "++show (tyConString' tc) ++ ", and fst tcl = "++show (fst tcl)) -- fromJust Nothing = error (show tc ++ " does not appear in the component library. Forgot to set one? BTW tc==funTyCon is "++show (tc==funTyCon)++" and funTyCon is "++show funTyCon) tyConString' tc = case tyConString tc of str@(',':_) -> '(':str++")" -- tyConString mistakenly prints "," instead of "(,)". str -> unqualify str -- Use the unqualified name to avoid confusion -- because Data.Typeable.tyConString shows the unqualified name -- for types defined in the Standard Hierarchical Library -- (though the qualified name is shown when Typeable is derived). unqualify :: String -> String unqualify = reverse . takeWhile (/='.') . reverse -- Do the following, because (mkTyCon "(->)") may or may not be equivalent to TyCon for functions in general. funTyCon :: Data.Typeable.TyCon funTyCon = typeRepTyCon (mkFunTy undefTC undefTC) -- undef = error "funTyCon" -- Dunno why, but seemingly mkFunTy is strict. undefTC = mkTyConApp (mkTyCon "Hoge") [] trToTHType :: TypeRep -> TH.Type trToTHType tr = case splitTyConApp tr of (tc,trs) -> if tc == funTyCon || show tc == show funTyCon -- dunno why, but sometimes |tc==funTyCon| is not enough. then TH.AppT TH.ArrowT (trToTHType (head trs)) `TH.AppT` trToTHType (head (tail trs)) else foldl TH.AppT (TH.ConT (TH.mkName (tyConString tc))) (map trToTHType trs) where tyConToName str = case tyConString str of "[]" -> TH.ListT str@(',':_) -> TH.TupleT (length str) -- tyConString mistakenly prints "," instead of "(,)". str -> TH.ConT $ TH.mkName str