{-# LANGUAGE TypeFamilies #-} -- | The internal representation of types, created by the type checker -- from the syntactic types in 'AST.Type'. module Type.Internal ( -- * Data definitions -- ** Types Quant(..), TyVar(..), Type(..), TyCon(..), -- ** Qualifiers QLit(..), QExp(..), QExpV, -- ** Type patterns TyPat(..), -- ** Kind re-exports Variance(..), Lattice(..), BoundedLattice(..), isQVariance, -- ** Names Name, TypId, QTypId, ConId, QConId, RowLabel, RecLabel, -- * Qualifiers Qualifier(..), qlitexp, qvarexp, extractQual, liftVQExp, mapQExp, -- * Type constructors abstractTyCon, mkTC, -- ** Built-in tcUnit, tcInt, tcChar, tcFloat, tcString, tcExn, tcTuple, tcFun, tcUn, tcAf, tcJoin, tcRowEnd, tcRecord, tcVariant, tcRowMap, tcRowDots, tcRowHole, -- ** Convenient constructors and projections fvTy, bvTy, fromFreeTV, -- ** Pre-constructed types tyNulOp, tyUnOp, tyBinOp, tyFun, tyArr, tyLol, tyTuple, tyQLit, tyAf, tyUn, tyUnit, tyInt, tyChar, tyFloat, tyString, tyExn, tyRecord, tyRowEnd, tyRowMap, tyRowHole, (.->.), (.-*.), (.*.), -- *** For testing tcCycle, tcConst, tcIdent, tcConsTup, tcOption, tcIdfun, tcSessOne, tcSessSend, tcSessRecv, tcSessSemi, tcSessDual, -- * Standard forms standardizeType, standardizeQuals, -- * Unfolds and folds -- ** Type folding foldType, foldTypeM, foldTypeEnv, mkBvF, mkQuF, mkMuF, -- ** Unfolds unfoldQu, unfoldRow, unfoldMu, -- ** Row operations foldRow, sortRow, -- * Locally nameless openTy, openTyN, closeTy, lcTy, lcTyK, closeRec, closeQuant, -- * Varieties TyConVariety(..), varietyOf, module Data.Empty, ) where import Util import Util.MonadRef import Data.Empty import Data.Lattice import Error import qualified Env import qualified AST import AST ( QLit(..), Variance(..), isQVariance ) import Prelude () import Control.Monad.ST import Data.Generics (Typeable, Data) import Data.STRef (STRef) import qualified Data.List as List import qualified Data.Map as M import qualified Data.Set as S --- --- DATA TYPES --- -- | Everything should be renamed by now type R = AST.Renamed type TypId = AST.TypId R type QTypId = AST.QTypId R type ConId = AST.ConId R type QConId = AST.QConId R type RowLabel = AST.Uid R type RecLabel = AST.Lid R -- | Optional names that don't affect α equivalence type Name = Perhaps String -- | Locally-nameless–style type variable occurrences in internal types data TyVar tv -- | A free type variable = Free !tv -- | A bound type variable | Bound !Int !Int !Name deriving (Eq, Ord, Functor, Typeable, Data) -- | Quantifiers data Quant -- | Universal quantifier = Forall -- | Existential quantifier | Exists deriving (Eq, Ord, Typeable, Data) -- | The internal representation of a type data Type tv -- | A free type variable = TyVar !(TyVar tv) -- | A quantified (all or ex) type | TyQu !Quant ![(Name, QLit)] !(Type tv) -- | A recursive (mu) type | TyMu !Name !(Type tv) -- | A row type | TyRow !RowLabel !(Type tv) !(Type tv) -- | The application of a type constructor (possibly nullary). | TyApp !TyCon ![Type tv] deriving (Functor, Typeable, Data) -- | Internal qualifier expressions data QExp tv -- | The type qualifier expression = QeA -- | The join of a set of type variables | QeU !(S.Set tv) deriving (Eq, Typeable, Data) -- | Qualifier expressions containing bound variables type QExpV tv = QExp (TyVar tv) -- | Information about a type constructor data TyCon = TyCon { -- | Unique ID tcId ∷ !Int, -- | Printable name tcName ∷ !QTypId, -- | Variances for parameters, and correct length tcArity ∷ ![Variance], -- | Bounds for parameters tcBounds ∷ ![QLit], -- | Guards recursive types tcGuards ∷ ![Bool], -- | Qualifier as a function of parameters tcQual ∷ !(QExp Int), -- | For pattern-matchable types, the data constructors, -- where type parameters are bound at level 0 tcCons ∷ !(Env.Env ConId (Maybe (Type Empty))), -- | For type operators, the next head reduction tcNext ∷ !(Maybe [([TyPat], Type Empty)]) } deriving (Typeable, Data) -- | A type pattern, for defining type operators data TyPat -- | A type variable, matching any type and binding = TpVar !Name -- | A type application node, matching the given constructor -- and its parameters | TpApp !TyCon ![TyPat] -- | A row type pattern | TpRow !Name deriving (Typeable, Data) instance Eq TyCon where tc == tc' = tcId tc == tcId tc' instance Ord TyCon where compare tc tc' = compare (tcName tc) (tcName tc') --- --- Abstracting type constructors --- -- | Remove the representation from a type constructor abstractTyCon ∷ TyCon → TyCon abstractTyCon tc = tc { tcCons = mempty, tcNext = Nothing } --- --- Built-in types --- class ExtTC r where extTC ∷ TyCon → r instance ExtTC TyCon where extTC = id instance ExtTC r ⇒ ExtTC (QTypId → r) where extTC tc x = extTC (tc { tcName = x }) instance (v ~ Variance, ql ~ QLit, ExtTC r) ⇒ ExtTC ([(v, ql, Bool)] → r) where extTC tc x = extTC tc { tcArity = sel1 <$> x, tcBounds = sel2 <$> x, tcGuards = sel3 <$> x } instance (tv ~ Int, ExtTC r) ⇒ ExtTC (QExp tv → r) where extTC tc x = extTC (tc { tcQual = x }) instance (a ~ Type Empty, ExtTC r) ⇒ ExtTC (Env.Env ConId (Maybe a) → r) where extTC tc x = extTC (tc { tcCons = x }) instance (t ~ Type Empty, ExtTC r) ⇒ ExtTC ([([TyPat], t)] → r) where extTC tc x = extTC (tc { tcNext = Just x }) mkTC ∷ ExtTC r ⇒ Int → AST.QTypId R → r mkTC i ql = extTC TyCon { tcId = i, tcName = ql, tcArity = [], tcBounds = [], tcGuards = [], tcQual = minBound, tcCons = Env.empty, tcNext = Nothing } internalTC ∷ ExtTC r ⇒ Int → String → r internalTC i s = mkTC i (AST.J [] (AST.identT (AST.Ren_ i) s)) tcUnit, tcInt, tcChar, tcFloat, tcString, tcExn, tcUn, tcAf, tcJoin, tcTuple, tcFun, tcRowEnd, tcRecord, tcVariant, tcRowMap, tcRowDots, tcRowHole ∷ TyCon tcFun = internalTC (-1) "->" (qvarexp 1) [(Contravariant, Qa, False), (QCovariant, Qa, False), (Covariant, Qa, False)] tcUnit = internalTC (-2) "unit" (Env.fromList [(AST.ident "()" ∷ ConId, Nothing)]) tcInt = internalTC (-3) "int" tcChar = internalTC (-4) "char" tcFloat = internalTC (-5) "float" tcString = internalTC (-6) "string" tcExn = internalTC (-7) "exn" QeA tcUn = internalTC (-8) "U" tcAf = internalTC (-9) "A" QeA tcJoin = internalTC (-10) "\\/" (qvarexp 0 ⊔ qvarexp 1) [(Covariant, Qa, False), (Covariant, Qa, False)] tcTuple = internalTC (-11) "*" (qvarexp 0 ⊔ qvarexp 1) [(Covariant, Qa, False), (Covariant, Qa, False)] tcRowEnd = internalTC (-12) "rowend" tcVariant = internalTC (-13) "variant" (qvarexp 0) [(Covariant, Qa, False)] tcRecord = internalTC (-14) "record" (qvarexp 1) [(QCovariant, Qa, False), (Covariant, Qa, False)] tcRowMap = internalTC (-15) "rowmap#" (qvarexp 0 ⊔ qvarexp 1) [(Covariant, Qa, False), (Invariant, Qa, False)] tcRowDots = internalTC (-16) "rowdots#" (qvarexp 0) [(Covariant, Qa, True)] tcRowHole = internalTC (-17) "rowhole#" (qvarexp 0) [(Covariant, Qa, True)] -- Types for testing tcCycle, tcConst, tcIdent, tcConsTup, tcOption, tcIdfun ∷ TyCon tcCycle = internalTC (-51) "cycle" [(Invariant, Qa, True)] tcConst = internalTC (-52) "const" [(Omnivariant, Qa, False)] [([TpVar Nope], tyUnit)] tcIdent = internalTC (-53) "ident" (qvarexp 0) [(Covariant, Qa, False)] [([TpVar Nope], TyVar (Bound 0 0 Nope))] tcConsTup = internalTC (-54) "cons" (qvarexp 0 ⊔ qvarexp 1) [(Covariant, Qa, False), (Covariant, Qa, False)] [([TpVar Nope, TpApp tcTuple [TpVar Nope, TpVar Nope]], TyApp tcTuple [TyApp tcConsTup [TyVar (Bound 0 0 Nope), TyVar (Bound 0 1 Nope)], TyVar (Bound 0 2 Nope)]), ([TpVar Nope, TpVar Nope], TyApp tcTuple [TyVar (Bound 0 0 Nope), TyVar (Bound 0 1 Nope)])] tcOption = internalTC (-55) "option" (qvarexp 0) [(Covariant, Qa, False)] (Env.fromList [(AST.ident "None" ∷ ConId, Nothing), (AST.ident "Some", Just (bvTy 0 0 Nope))]) tcIdfun = internalTC (-55) "idfun" [(Invariant, Qa, False)] (Env.fromList [(AST.ident "Mono" ∷ ConId, Just (bvTy 0 0 Nope .->. bvTy 0 0 Nope)), (AST.ident "Poly", Just (TyQu Forall [(Nope, Qa)] (bvTy 0 0 Nope .->. bvTy 0 0 Nope)))]) tcSessOne, tcSessSend, tcSessRecv, tcSessSemi, tcSessDual ∷ TyCon tcSessOne = internalTC (-56) "1" tcSessSend = internalTC (-57) "!" [(-1, Qa, False)] tcSessRecv = internalTC (-58) "?" [(1, Qa, False)] tcSessSemi = internalTC (-59) ";" [(1, Qu, False), (1, Qu, True)] tcSessDual = internalTC (-60) "dual" [(-1, Qu, False)] [([TpApp tcSessOne []], TyApp tcSessOne []), ([TpApp tcSessSemi [TpApp tcSessSend [TpVar Nope], TpVar Nope]], TyApp tcSessSemi [TyApp tcSessRecv [TyVar (Bound 0 0 Nope)], TyApp tcSessDual [TyVar (Bound 0 1 Nope)]]), ([TpApp tcSessSemi [TpApp tcSessRecv [TpVar Nope], TpVar Nope]], TyApp tcSessSemi [TyApp tcSessSend [TyVar (Bound 0 0 Nope)], TyApp tcSessDual [TyVar (Bound 0 1 Nope)]])] --- --- Convenience constructors --- -- | Make a free type variable into a type fvTy ∷ tv → Type tv fvTy = TyVar . Free -- | Make a bound type variable type bvTy ∷ Optional f ⇒ Int → Int → f String → Type tv bvTy i j n = TyVar (Bound i j (foldOpt Nope Here n)) -- | Project a free type variable from a 'TyVar' fromFreeTV ∷ TyVar tv → tv fromFreeTV (Free r) = r fromFreeTV _ = throw $ almsBug StaticsPhase "fromFreeTV" "Got bound type variable" -- | Make a type from a nullary type constructor tyNulOp ∷ TyCon → Type tv tyNulOp tc = TyApp tc [] -- | Make a type from a unary type constructor tyUnOp ∷ TyCon → Type tv → Type tv tyUnOp tc t1 = TyApp tc [t1] -- | Make a type from a binary type constructor tyBinOp ∷ TyCon → Type tv → Type tv → Type tv tyBinOp tc t1 t2 = TyApp tc [t1, t2] -- | A function type tyFun ∷ Qualifier qe tv ⇒ Type tv → qe → Type tv → Type tv tyFun t1 qe t2 = TyApp tcFun [t1, qualToType qe, t2] -- | Constructor for unlimited arrow types tyArr ∷ Type tv → Type tv → Type tv tyArr = tyFun <-> Qu -- | Constructor for affine arrow types tyLol ∷ Type tv → Type tv → Type tv tyLol = tyFun <-> Qa -- | Type from a 'QLit' tyQLit ∷ QLit → Type tv tyQLit Qa = tyAf tyQLit Qu = tyUn -- | Binary types tyTuple, tyRowMap, tyRecord ∷ Type tv → Type tv → Type tv tyTuple = tyBinOp tcTuple tyRowMap = tyBinOp tcRowMap tyRecord = tyBinOp tcRecord -- | Nullary types tyAf, tyUn, tyUnit, tyInt, tyChar, tyFloat, tyString, tyExn, tyRowEnd, tyRowHole ∷ Type tv tyAf = tyNulOp tcAf tyUn = tyNulOp tcUn tyUnit = tyNulOp tcUnit tyInt = tyNulOp tcInt tyChar = tyNulOp tcChar tyFloat = tyNulOp tcFloat tyString = tyNulOp tcString tyExn = tyNulOp tcExn tyRowEnd = tyNulOp tcRowEnd tyRowHole= tyNulOp tcRowHole (.*.), (.->.), (.-*.) ∷ Type tv → Type tv → Type tv (.*.) = tyTuple (.->.) = tyArr (.-*.) = tyLol infixr 6 .->., .-*., `tyArr`, `tyLol` infixl 7 .*., `tyTuple` --- --- Qualifiers --- instance Ord tv ⇒ Lattice (QExp tv) where QeA ⊔ _ = QeA _ ⊔ QeA = QeA QeU tvs ⊔ QeU tvs' = QeU (tvs `S.union` tvs') -- QeA ⊓ qe' = qe' qe ⊓ QeA = qe QeU tvs ⊓ QeU tvs' = QeU (tvs `S.intersection` tvs') -- _ ⊑ QeA = True QeA ⊑ _ = False QeU tvs ⊑ QeU tvs' = tvs `S.isSubsetOf` tvs' instance Bounded (QExp tv) where minBound = QeU S.empty maxBound = QeA class Qualifier q tv | q → tv where qualToType ∷ q → Type tv qualifierEnv ∷ Ord tv ⇒ [[QLit]] → q → QExpV tv qualifier ∷ Ord tv ⇒ q → QExpV tv qualifierEnv = const qualifier qualifier = qualifierEnv [] instance Qualifier q tv ⇒ Qualifier (Maybe q) tv where qualToType = maybe tyUn qualToType qualifierEnv = maybe minBound . qualifierEnv instance (Ord tv, Qualifier q tv) ⇒ Qualifier [q] tv where qualToType = qualToType . qualifier qualifierEnv = bigJoin <$$> map . qualifierEnv instance Qualifier QLit tv where qualToType Qa = tyAf qualToType Qu = tyUn qualifier Qa = QeA qualifier Qu = QeU S.empty instance Qualifier AST.Occurrence tv where qualToType = qualToType . AST.occToQLit qualifier = qualifier . AST.occToQLit instance Ord tv ⇒ Qualifier (Type tv) tv where qualToType = qualToType . qualifier qualifierEnv env0 = foldTypeEnv (Left <$$> env0) fquant fbvar ffvar fcon frow frec where fquant ∷ Quant → [(Name, QLit)] → ([Either QLit QLit] → (QExpV tv → QExpV tv) → a) → a frec ∷ Name → (Either QLit QLit → (QExpV tv → QExpV tv) → a) → a fquant Forall αs k = k (Right Qu <$ αs) bumpQExp fquant Exists αs k = k (Right . snd <$> αs) bumpQExp fbvar _ _ (Just (Right ql)) = qlitexp ql fbvar _ _ (Just (Left Qu)) = qlitexp Qu fbvar (i,j) n _ = qvarexp (Bound i j n) ffvar = qvarexp . Free fcon tc qes = extractQual (tcQual tc) qes frow _ qe1 qe2 = qe1 ⊔ qe2 frec _ k = k (Right Qu) bumpQExp -- bumpQExp QeA = QeA bumpQExp (QeU tvs) = QeU (S.map (bumpVar (-1)) tvs) bumpVar _ (Free r) = Free r bumpVar k (Bound i j n)= Bound (i + k) j n instance Qualifier (QExpV tv) tv where qualToType QeA = TyApp tcAf [] qualToType (QeU tvs) | S.null tvs = TyApp tcUn [] | otherwise = foldr1 (\t1 t2 → TyApp tcJoin [t1, t2]) (TyVar <$> S.toList tvs) qualifier = id instance Qualifier (S.Set tv) tv where qualifier αs = QeU (S.mapMonotonic Free αs) qualToType αs = qualToType (QeU (S.mapMonotonic Free αs)) -- | Make a qualifier expression from a single literal qlitexp ∷ QLit → QExp tv qlitexp Qa = QeA qlitexp Qu = QeU S.empty -- | Make a qualifier expression from a single type variable qvarexp ∷ tv → QExp tv qvarexp = QeU . S.singleton -- | Build a qualifier from a list of qualifiers using an -- integer-numbered qualifier. extractQual ∷ Ord tv ⇒ QExp Int → [QExp tv] → QExp tv extractQual QeA _ = QeA extractQual (QeU zs) qes = bigJoin (fst <$> filter ((`elem` zs) . snd) (zip qes [0 ..])) -- | Lift a free-variable q-expression to a 'QExpV' liftVQExp ∷ QExp tv → QExpV tv liftVQExp QeA = QeA liftVQExp (QeU αs) = QeU (S.mapMonotonic Free αs) -- | Modify the set of a 'QeU' 'QExp" mapQExp ∷ (S.Set tv → S.Set tv') → QExp tv → QExp tv' mapQExp _ QeA = QeA mapQExp f (QeU αs) = QeU (f αs) --- --- Folds and unfolds --- foldTypeEnv ∷ Ord tv ⇒ -- | Initial environment [[s]] → -- | For quantifiers (∀a. Quant → [(Name, QLit)] → ([s] → (r → r) → a) → a) → -- | For bound variables ((Int, Int) → Name → Maybe s → r) → -- | For free variables (tv → r) → -- | For constructor applications (TyCon → [r] → r) → -- | For row type labels (RowLabel → r → r → r) → -- | For recursive types (∀a. Name → (s → (r → r) → a) → a) → -- | Type to fold Type tv → r foldTypeEnv env0 fquant fbvar ffvar fcon frow frec σ0 = runReader (loop σ0) env0 where loop (TyQu q αs σ) = fquant q αs $ \ss f → f `liftM` local (ss:) (loop σ) loop (TyVar (Bound i j n)) = do env ← ask return (fbvar (i, j) n (look i j env)) loop (TyVar (Free v)) = return (ffvar v) loop (TyApp tc ts) = fcon tc <$> sequence [ if isQVariance v then loop (qualToType t) else loop t | t ← ts | v ← tcArity tc ] loop (TyRow n t1 t2) = frow n `liftM` loop t1 `ap` loop t2 loop (TyMu n t) = frec n (\s f → f `liftM` local ([s]:) (loop t)) -- look i j env | rib:_ ← drop i env , elt:_ ← drop j rib = Just elt look _ _ _ = Nothing foldType ∷ Ord tv ⇒ -- | For quantifiers (∀a. Quant → [(Name, QLit)] → ([s] → (r → r) → a) → a) → -- | For bound variables ((Int, Int) → Name → Maybe s → r) → -- | For free variables (tv → r) → -- | For constructor applications (TyCon → [r] → r) → -- | For row type labels (RowLabel → r → r → r) → -- | For recursive types (∀a. Name → (s → (r → r) → a) → a) → -- | Type to fold Type tv → r foldType = foldTypeEnv [] -- | Helper for constructing bound variable case for 'foldType' mkBvF ∷ (Int → Int → Name → r) → (Int, Int) → Name → a → r mkBvF f (i, j) pn _ = f i j pn -- | Helper for constructing quantifier case for 'foldType' mkQuF ∷ (Quant → [(Name, QLit)] → r → s) → (∀a. Quant → [(Name, QLit)] → ([(Int, Int)] → (r → s) → a) → a) mkQuF f q αs k = k [ (0, j) | j ← [0 .. length αs - 1] ] (f q αs) -- | Helper for constructing recursive case for 'foldType' mkMuF ∷ (Name → r → s) → (∀a. Name → ((Int, Int) → (r → s) → a) → a) mkMuF f pn k = k (0, 0) (f pn) foldTypeM ∷ (Monad m, Ord tv) ⇒ -- | For quantifiers (∀a. Quant → [(Name, QLit)] → ([s] → (r → m r) → a) → a) → -- | For bound variables ((Int, Int) → Name → Maybe s → m r) → -- | For free variables (tv → m r) → -- | For constructor applications (TyCon → [r] → m r) → -- | For row type labels (RowLabel → r → r → m r) → -- | For recursive types (∀a. Name → (s → (r → m r) → a) → a) → -- | Type to fold Type tv → m r foldTypeM fquant fbvar ffvar fapp frow frec = foldType (\qu ns k → fquant qu ns (\s k' → k s (>>= k'))) fbvar ffvar (\tc mrs → sequence mrs >>= fapp tc) (\lab mr1 mr2 → mr1 >>= \r1 → mr2 >>= frow lab r1) (\n k → frec n (\s k' → k s (>>= k'))) -- -- Other unfolds -- -- To strip off as many of the specified quantifier as possible, -- building a qualifier bound environment for the layers. unfoldQu ∷ Quant → Type tv → ([[QLit]], Type tv) unfoldQu u0 = first reverse . loop where loop (TyQu u tvs t) | u0 == u || lcTyK 0 t = first (map snd tvs:) (loop t) loop t = ([], t) -- To find the labels and fields of a row type, and the extension, -- in standard order unfoldRow ∷ Type tv → ([(RowLabel, Type tv)], Type tv) unfoldRow = first (List.sortBy (compare <$> fst <$.> fst)) . loop where loop (TyRow n t1 t2) = first ((n, t1):) (loop t2) loop t = ([], t) -- Unfold leading μ (recursive type) binders. unfoldMu ∷ Type tv → ([Name], Type tv) unfoldMu (TyMu pn t) = first (pn:) (unfoldMu t) unfoldMu t = ([], t) --- --- Row operations --- -- Construct a row from a list of label/type pairs and a tail type. foldRow ∷ [(RowLabel, Type a)] → Type a → Type a foldRow = flip (foldr (uncurry TyRow)) -- Sort a row by its labels sortRow ∷ Type a → Type a sortRow = uncurry foldRow . unfoldRow --- --- Type standardization --- -- | @standardize@ puts a type in standard form. -- A type is in standard form if three conditions are met: -- -- * All bound type variables actually appear in their scope. That -- is, ‘∀ α β γ. α → γ’ is not standard, but ‘∀ α γ. α → γ’ is. -- -- * The same quantifier never nests directly inside itself. That is, -- ‘∀ α β. ∀ γ. C α β γ’ is not standard, but ‘∀ α β γ. C α β γ’ is. -- -- * The bound type variables of each quantifier are listed in the -- order that they appear in its scope. That is, -- ‘∀ α β γ. C α γ β’ is not standard, but ‘∀ α β γ. C α β γ’ is. -- -- * Type variables bound by μ appear in their scope, and there are -- never multiple, immediately nested μs. -- -- Type standardization is necessary as a post-pass after parsing, -- because it's difficult to parse into standard form directly. standardizeType ∷ Ord tv ⇒ Type tv → Type tv standardizeType = standardizeQuals M.empty -- | Used in the definition of 'standardizeQuals' below. type StdizeEnv s = [[(Int, STRef s [((Int, Int), (Name, QLit))], Bool, QLit)]] -- | Standardize a type while cleaning up qualifiers. standardizeQuals ∷ ∀tv. Ord tv ⇒ M.Map tv QLit → Type tv → Type tv standardizeQuals qm t00 = runST (loop 0 [] t00) where loop ∷ ∀s. Int → StdizeEnv s → Type tv → ST s (Type tv) loop depth g t0 = case t0 of TyQu u _ _ → do rn ← newRef [] let (qls, t) = unfoldQu u t0 i = length qls g' = (depth + i, rn, False,) <$$> qls t' ← loop (depth + i) (g' ++ g) t nl ← readRef rn return $ case nl of [] → openTyN i (-1) [] t' _ → TyQu u [ n | (_,n) ← nl ] (openTyN (i - 1) (i - 1) [] t') TyApp tc ts → TyApp tc <$> sequence [ if isQVariance v then doQual depth g t else loop depth g t | t ← ts | v ← tcArity tc ] TyVar v → TyVar . fst <$> doVar depth g (const True) v TyRow _ _ _ → do let (row, ext) = unfoldRow t0 row' ← sequence [ (ni,) <$> loop depth g ti | (ni, ti) ← row ] ext' ← loop depth g ext return (foldRow row' ext') TyMu pn _ → do rn ← newRef [] let (pns, t) = unfoldMu t0 i = length pns g' = (depth + i, rn, True,) <$$> replicate i [Qa] t' ← loop (depth + i) (g' ++ g) t nl ← readRef rn return $ if null nl then openTyN i (-1) [] t' else TyMu pn (openTyN (i - 1) (i - 1) [] t') -- doVar ∷ ∀s. Int → StdizeEnv s → (QLit → Bool) → TyVar tv → ST s (TyVar tv, Bool) doVar depth g keep v0 = case v0 of Bound i j n | rib:_ ← drop i g , (olddepth, r, rec, ql):_ ← drop j rib → do s ← readRef r if rec then do case List.findIndex ((== (depth - i)) . fst . fst) s of Just _ → return () Nothing → writeRef r (s ++ [((depth - i, 0), (n, ql))]) return (Bound (depth - olddepth) 0 n, True) else do j' ← case List.findIndex ((== (depth - i, j)) . fst) s of Just j' → return j' Nothing → do when (keep ql) $ writeRef r (s ++ [((depth - i, j), (n, ql))]) return (length s) return (Bound (depth - olddepth) j' n, keep ql) | otherwise → return (v0, True) Free r → return (Free r, keep (M.findWithDefault maxBound r qm)) -- doQual ∷ ∀s. Ord tv ⇒ Int → StdizeEnv s → Type tv → ST s (Type tv) doQual depth g t = qualToType <$> case qualifier t of QeA → return QeA QeU tvs → do tvbs' ← mapM (doVar depth g (== Qa)) (S.toList tvs) return (QeU (S.fromList (fst <$> filter snd tvbs'))) --- --- Locally-nameless operations --- -- | @openTy k τs τ@ substitutes @τs@ for the bound type variables at -- rib level @k@. DeBruijn indices higher than @k@ are adjusted downward, -- since opening a type peels off a quantifier. openTy ∷ Int → [Type a] → Type a → Type a openTy = openTyN 1 -- | Generalization of 'openTy': the first argument specifies how much -- to adjust indices that exceed @k@. openTyN ∷ Int → Int → [Type a] → Type a → Type a openTyN n k vs σ0 = case σ0 of TyQu u e σ → TyQu u e (next σ) TyVar v → openTV_N n k vs v TyApp name σs → TyApp name (map this σs) TyRow name σ1 σ2 → TyRow name (this σ1) (this σ2) TyMu name σ → TyMu name (next σ) where this = openTyN n k vs next = openTyN n (k + 1) vs openTV_N ∷ Int → Int → [Type a] → TyVar a → Type a openTV_N n k vs (Bound i j name) | i > k = TyVar (Bound (i - n) j name) | i == k, Just σ ← listNth j vs = σ | otherwise = TyVar (Bound i j name) openTV_N _ _ _ (Free v) = TyVar (Free v) -- | @closeTy k αs τ@ finds the free variables @αs@ and replaces them -- with bound variables at rib level @k@. The position of each type -- variable in @αs@ gives the index of each bound variable into the -- new rib. closeTy ∷ Eq a ⇒ Int → [a] → Type a → Type a closeTy k vs σ0 = case σ0 of TyQu u e σ → TyQu u e (next σ) TyVar (Bound i j n) | i >= k → TyVar (Bound (i + 1) j n) | otherwise → TyVar (Bound i j n) TyVar (Free v) | Just j ← List.findIndex (== v) vs → TyVar (Bound k j Nope) | otherwise → TyVar (Free v) TyApp n σs → TyApp n (map this σs) TyRow n σ1 σ2 → TyRow n (this σ1) (this σ2) TyMu n σ → TyMu n (next σ) where this = closeTy k vs next = closeTy (k + 1) vs -- | Build a recursive type by closing and binding the given variable closeRec ∷ Ord tv ⇒ tv → Type tv → Type tv closeRec α σ = standardizeType (TyMu Nope (closeTy 0 [α] σ)) -- | Add the given quantifier while binding the given list of variables closeQuant ∷ Ord tv ⇒ Quant → [(tv, QLit)] → Type tv → Type tv closeQuant qu αqs ρ = standardizeType (TyQu qu nqs (closeTy 0 αs ρ)) where αs = fst <$> αqs nqs = zip (repeat Nope) (snd <$> αqs) -- | Is the given type locally closed to level k? A type is locally closed -- if none of its bound variables point to quantifiers "outside" the -- type. -- -- ASSUMPTION: No bound variables are lurking behind an apparent free -- variable, because @lcTy@ doesn't attempt to dereference free -- variables. This should be an invariant, because it would come -- about only as a result of a capturing substitution. lcTy ∷ Int → Type a → Bool lcTy = loop where loop k (TyQu _ _ t) = loop (k + 1) t loop k (TyVar (Bound i _ _)) = k > i loop _ (TyVar (Free _)) = True loop k (TyApp _ ts) = all (loop k) ts loop k (TyRow _ t1 t2) = loop k t1 && loop k t2 loop k (TyMu _ t) = loop (k + 1) t -- | Are there no bound vars of level k? lcTyK ∷ Int → Type tv → Bool lcTyK = loop where loop k (TyQu _ _ t) = loop (k + 1) t loop k (TyVar (Bound i _ _)) = k /= i loop _ (TyVar (Free _)) = True loop k (TyApp _ ts) = all (loop k) ts loop k (TyRow _ t1 t2) = loop k t1 && loop k t2 loop k (TyMu _ t) = loop (k + 1) t --- --- TyCon Varieties --- data TyConVariety = AbstractType | DataType | OperatorType deriving (Eq, Ord) -- | Find out the variety of a type constructor varietyOf ∷ TyCon → TyConVariety varietyOf tc | isJust (tcNext tc) = OperatorType | Env.isEmpty (tcCons tc) = AbstractType | otherwise = DataType