-- | Warning: there are a bunch of comments on the positional fields -- of constructors in this module (perhaps the constructors should be -- record constructors so that they can have docstrings on their -- fields?) module NT ( NT(..), NewType(..), Kind(..) , mkNTvar, mkNTexist, mkNTcons , anyNT, consNT, freeNT, freshNT, polyNT, strTVar , sndNTvar, strNT, strictNT, transCtxs, useNT , contextNT, ntContext2Pair, stripNT, anyVarNT ) where import Id(Id, strTVar) import Util.Extra(mixComma,mixSpace,mix) import Char infixr 5 :->: data Kind = Star | Kind :->: Kind deriving (Eq,Ord) -- | Perhaps @NewType@ is a type schema? It quantifies variables over -- an arrow of 'NT's. data NewType = NoType | NewType [Id] -- universally quantified type variables [Id] -- existentially quantified type variables [(Id,Id)] -- context (class, type variable) [NT] -- simple types -- ex.: [Int,Char,Bool] = Int->Char->Bool deriving (Eq) instance Show NewType where showsPrec d (NoType) = showString " -- no type --" showsPrec d (NewType free exist ctxs nts) = showString (strTVarsCtxsNTs free ctxs nts) data NT = NTany Id -- ^ can be instantiated with unboxed -- (needed during type checking) | NTvar Id Kind | NTexist Id Kind | NTstrict NT | NTapp NT NT | NTcons Id Kind [NT] -- ^ combines constructor + application | NTcontext Id Id -- ^ context (class, type variable) -- purpose here completely unclear (used?) deriving (Eq,Ord) mkNTvar, mkNTexist :: Id -> NT mkNTvar v = NTvar v Star -- simple tyvar mkNTexist v = NTexist v Star -- simple tyvar mkNTcons :: Id -> [NT] -> NT mkNTcons i nts = NTcons i kind nts -- where kind = foldr (:->:) Star (map kindNT nts) where kind = Star -- error "kind inference is not implemented correctly" kindNT :: NT -> Kind kindNT (NTany _) = Star kindNT (NTvar _ k) = k kindNT (NTexist _ k) = k kindNT (NTapp nt1 nt2) = case (kindNT nt1) of (_:->:k) -> k kindNT (NTcons _ k nts) = foldl (\(_:->:k') _ -> k') k nts kindNT (NTcontext _ _) = Star stripNT :: NT -> Id stripNT (NTany v) = v stripNT (NTvar v _) = v stripNT (NTexist v _) = v stripNT (NTapp (NTvar v _) nt ) = v stripNT nt = error ("stripNT on " ++ show nt) strictNT :: NT -> Bool strictNT (NTstrict _) = True strictNT _ = False ntContext2Pair :: NT -> (Id, Id) ntContext2Pair (NTcontext c a) = (c,a) contextNT :: NT -> Bool contextNT (NTcontext _ _) = True contextNT _ = False {- | Determine the type constructors that occur in the given type -} consNT :: NT -> [Id] consNT nt = consNT' nt [] where consNT' (NTstrict nt) r = consNT' nt r consNT' (NTapp t1 t2) r = consNT' t1 (consNT' t2 r) consNT' (NTcons c _ nts) r = c:foldr consNT' r nts consNT' _ r = r {- | Same as consNT except that constructor from NTcontext goes also into result. used only in module 'Export' -} useNT :: NT -> [Id] useNT (NTany a) = [] useNT (NTvar a _) = [] useNT (NTexist a _) = [] useNT (NTstrict t) = useNT t useNT (NTapp t1 t2) = useNT t1 ++ useNT t2 useNT (NTcons a _ tas) = a:concatMap useNT tas useNT (NTcontext c v) = [c] {- | Determine type variables that occur in given type. -} freeNT :: NT -> [Id] freeNT (NTany a) = [a] freeNT (NTvar a _) = [a] freeNT (NTexist a _) = [a] freeNT (NTstrict t) = freeNT t freeNT (NTapp t1 t2) = freeNT t1 ++ freeNT t2 freeNT (NTcons a _ tas) = concat (map freeNT tas) {- | Exchange type variables according to given mapping in given type. (not existentially quantified vars. -} freshNT :: (Id -> Id) -> NT -> NT freshNT tv (NTany a) = NTany (tv a) freshNT tv (NTvar a k) = NTvar (tv a) k freshNT tv t@(NTexist a _) = t freshNT tv (NTstrict t) = {- NTstrict -} (freshNT tv t) freshNT tv (NTapp t1 t2) = NTapp (freshNT tv t1) (freshNT tv t2) freshNT tv (NTcons a k tas) = NTcons a k (map (freshNT tv) tas) freshNT tv (NTcontext c v) = NTcontext c (tv v) anyNT :: [Id] -> NT -> NT anyNT av t@(NTany a) = t anyNT av t@(NTvar a _) = if a `elem` av then NTany a else t anyNT av t@(NTexist a _) = t anyNT av (NTstrict t) = NTstrict (anyNT av t) anyNT av (NTapp t1 t2) = NTapp (anyNT av t1) (anyNT av t2) anyNT av (NTcons a k tas) = NTcons a k (map (anyNT av) tas) polyNT :: [Id] -> NT -> NT polyNT fv t@(NTany a) = if a `elem` fv then mkNTvar a else t polyNT fv t@(NTvar a _) = t polyNT fv t@(NTexist a _) = t polyNT fv (NTstrict t) = NTstrict (polyNT fv t) polyNT fv (NTapp t1 t2) = NTapp (polyNT fv t1) (polyNT fv t2) polyNT fv (NTcons a k tas) = NTcons a k (map (polyNT fv) tas) -- | FIXME: Isn't this type a tad more general than appropriate for the name? transCtxs :: (a -> b) -> (c -> d) -> [(c, a)] -> [(d, b)] transCtxs tv tc ctxs = map (\(c,v) -> (tc c,tv v)) ctxs {- | Show function for 'NT', parameterised by show functions for constructors\/class names and for type variables. -} strNT :: (Id -> String) -> (Id -> String) -> NT -> String strNT c p (NTany a) = p a++"#" strNT c p (NTvar a _) = p a strNT c p (NTexist a _) = p a++"?" strNT c p (NTstrict t) = "!" ++ strNT c p t strNT c p (NTapp t1 t2) = "(" ++ strNT c p t1 ++ " " ++ strNT c p t2 ++ ")" strNT c p (NTcons a _ []) = c a strNT c p (NTcons a _ tas) = "(" ++ c a ++ " " ++ mixSpace (map (strNT c p) tas) ++ ")" strNT c p (NTcontext a v) = "(" ++ c a ++ " " ++ p a ++ ") => " instance Show NT where showsPrec d nt = ((strNT show (show ::(Id->String)) nt)++) strCtxs :: [(Id,Id)] -> String strCtxs [] = "" strCtxs ctxs = "(" ++ mixComma (map ( \ (c,v) -> show c ++ ' ':strTVar v ) ctxs) ++ ") => " strTVs :: [Id] -> String strTVs [] = "" strTVs tvs = "\\/ " ++ mixSpace (map strTVar tvs) ++ " . " strTVarsCtxsNTs :: [Id] -> [(Id, Id)] -> [NT] -> [Char] strTVarsCtxsNTs tvs ctxs [] = strTVs tvs ++ strCtxs ctxs ++ " -" strTVarsCtxsNTs tvs ctxs nts = strTVs tvs ++ strCtxs ctxs ++ mix " -> " (map (strNT show strTVar) nts) sndNTvar :: (a, Id) -> (a, NT) sndNTvar (c,v) = (c,mkNTvar v) -- used for ctxs *** KIND?? anyVarNT :: NT -> Maybe Id anyVarNT (NTany tvn) = Just tvn anyVarNT (NTvar tvn _) = Just tvn anyVarNT _ = Nothing