{-# OPTIONS -fno-warn-missing-signatures #-} module DDC.Type.Compounds ( -- * Binds takeNameOfBind , typeOfBind , replaceTypeOfBind -- * Binders , binderOfBind , makeBindFromBinder , partitionBindsByType -- * Bounds , takeNameOfBound , takeTypeOfBound , boundMatchesBind , namedBoundMatchesBind , takeSubstBoundOfBind , takeSubstBoundsOfBinds , replaceTypeOfBound -- * Kinds , kFun , kFuns , takeKFun , takeKFuns , takeKFuns' , takeResultKind -- * Quantifiers , tForall, tForall' , tForalls, tForalls' , takeTForalls, eraseTForalls -- * Sums , tBot , tSum -- * Applications , tApp, ($:) , tApps, takeTApps , takeTyConApps , takePrimTyConApps , takeDataTyConApps , takePrimeRegion -- * Functions , tFun, tFunOfList , tFunPE, tFunOfListPE , tFunEC , takeTFun, takeTFunEC , takeTFunArgResult , takeTFunWitArgResult , takeTFunAllArgResult , arityOfType -- * Suspensions , tSusp -- * Implications , tImpl -- * Units , tUnit -- * Variables , tIx , takeTExists -- * Sort construction , sComp, sProp -- * Kind construction , kData, kRegion, kEffect, kClosure, kWitness -- * Effect type constructors , tRead, tDeepRead, tHeadRead , tWrite, tDeepWrite , tAlloc, tDeepAlloc -- * Closure type constructors , tUse, tDeepUse -- * Witness type constructors , tPure , tEmpty , tGlobal, tDeepGlobal , tConst, tDeepConst , tMutable, tDeepMutable , tDistinct , tLazy, tHeadLazy , tManifest , tConData0, tConData1) where import DDC.Type.Exp import qualified DDC.Type.Sum as Sum -- Binds ---------------------------------------------------------------------- -- | Take the variable name of a bind. -- If this is an anonymous binder then there won't be a name. takeNameOfBind :: Bind n -> Maybe n takeNameOfBind bb = case bb of BName n _ -> Just n BAnon _ -> Nothing BNone _ -> Nothing -- | Take the type of a bind. typeOfBind :: Bind n -> Type n typeOfBind bb = case bb of BName _ t -> t BAnon t -> t BNone t -> t -- | Replace the type of a bind with a new one. replaceTypeOfBind :: Type n -> Bind n -> Bind n replaceTypeOfBind t bb = case bb of BName n _ -> BName n t BAnon _ -> BAnon t BNone _ -> BNone t -- Binders -------------------------------------------------------------------- -- | Take the binder of a bind. binderOfBind :: Bind n -> Binder n binderOfBind bb = case bb of BName n _ -> RName n BAnon _ -> RAnon BNone _ -> RNone -- | Make a bind from a binder and its type. makeBindFromBinder :: Binder n -> Type n -> Bind n makeBindFromBinder bb t = case bb of RName n -> BName n t RAnon -> BAnon t RNone -> BNone t -- | Make lists of binds that have the same type. partitionBindsByType :: Eq n => [Bind n] -> [([Binder n], Type n)] partitionBindsByType [] = [] partitionBindsByType (b:bs) = let t = typeOfBind b bsSame = takeWhile (\b' -> typeOfBind b' == t) bs rs = map binderOfBind (b:bsSame) in (rs, t) : partitionBindsByType (drop (length bsSame) bs) -- Bounds --------------------------------------------------------------------- -- | Take the name of bound variable. -- If this is a deBruijn index then there won't be a name. takeNameOfBound :: Bound n -> Maybe n takeNameOfBound uu = case uu of UName n -> Just n UPrim n _ -> Just n UIx{} -> Nothing -- | Get the attached type of a `Bound`, if any. takeTypeOfBound :: Bound n -> Maybe (Type n) takeTypeOfBound uu = case uu of UName{} -> Nothing UPrim _ t -> Just t UIx{} -> Nothing -- | Check whether a bound maches a bind. -- `UName` and `BName` match if they have the same name. -- @UIx 0 _@ and @BAnon _@ always match. -- Yields `False` for other combinations of bounds and binds. boundMatchesBind :: Eq n => Bound n -> Bind n -> Bool boundMatchesBind u b = case (u, b) of (UName n1, BName n2 _) -> n1 == n2 (UIx 0, BAnon _) -> True _ -> False -- | Check whether a named bound matches a named bind. -- Yields `False` if they are not named or have different names. namedBoundMatchesBind :: Eq n => Bound n -> Bind n -> Bool namedBoundMatchesBind u b = case (u, b) of (UName n1, BName n2 _) -> n1 == n2 _ -> False -- | Convert a `Bind` to a `Bound`, ready for substitution. -- -- Returns `UName` for `BName`, @UIx 0@ for `BAnon` -- and `Nothing` for `BNone`, because there's nothing to substitute. takeSubstBoundOfBind :: Bind n -> Maybe (Bound n) takeSubstBoundOfBind bb = case bb of BName n _ -> Just $ UName n BAnon _ -> Just $ UIx 0 BNone _ -> Nothing -- | Convert some `Bind`s to `Bounds` takeSubstBoundsOfBinds :: [Bind n] -> [Bound n] takeSubstBoundsOfBinds bs = go 1 bs where go _level [] = [] go level (BName n _ : bs') = UName n : go level bs' go level (BAnon _ : bs') = UIx (len - level) : go (level + 1) bs' go level (BNone _ : bs') = go level bs' len = length [ () | BAnon _ <- bs] -- | If this `Bound` is a `UPrim` then replace it's embedded type with a new -- one, otherwise return it unharmed. replaceTypeOfBound :: Type n -> Bound n -> Bound n replaceTypeOfBound t uu = case uu of UName{} -> uu UPrim n _ -> UPrim n t UIx{} -> uu -- Variables ------------------------------------------------------------------ -- | Construct a deBruijn index. tIx :: Kind n -> Int -> Type n tIx _ i = TVar (UIx i) -- Existentials --------------------------------------------------------------- -- | Take an existential variable from a type. takeTExists :: Type n -> Maybe Int takeTExists tt = case tt of TCon (TyConExists n _) -> Just n _ -> Nothing -- Applications --------------------------------------------------------------- -- | Construct an empty type sum. tBot :: Kind n -> Type n tBot k = TSum $ Sum.empty k -- | Construct a type application. tApp, ($:) :: Type n -> Type n -> Type n tApp = TApp ($:) = TApp -- | Construct a sequence of type applications. tApps :: Type n -> [Type n] -> Type n tApps t1 ts = foldl TApp t1 ts -- | Flatten a sequence ot type applications into the function part and -- arguments, if any. takeTApps :: Type n -> [Type n] takeTApps tt = case tt of TApp t1 t2 -> takeTApps t1 ++ [t2] _ -> [tt] -- | Flatten a sequence of type applications, returning the type constructor -- and arguments, if there is one. takeTyConApps :: Type n -> Maybe (TyCon n, [Type n]) takeTyConApps tt = case takeTApps tt of TCon tc : args -> Just $ (tc, args) _ -> Nothing -- | Flatten a sequence of type applications, returning the type constructor -- and arguments, if there is one. Only accept primitive type constructors. takePrimTyConApps :: Type n -> Maybe (n, [Type n]) takePrimTyConApps tt = case takeTApps tt of TCon tc : args | TyConBound (UPrim n _) _ <- tc -> Just (n, args) _ -> Nothing -- | Flatten a sequence of type applications, returning the type constructor -- and arguments, if there is one. Only accept data type constructors. takeDataTyConApps :: Type n -> Maybe (TyCon n, [Type n]) takeDataTyConApps tt = case takeTApps tt of TCon tc : args | TyConBound (UName{}) k <- tc , TCon (TyConKind KiConData) <- takeResultKind k -> Just (tc, args) _ -> Nothing -- | Take the prime region variable of a data type. -- This corresponds to the region the outermost constructor is allocated into. takePrimeRegion :: Type n -> Maybe (Type n) takePrimeRegion tt = case takeTApps tt of TCon _ : tR@(TVar _) : _ -> Just tR _ -> Nothing -- Foralls -------------------------------------------------------------------- -- | Build an anonymous type abstraction, with a single parameter. tForall :: Kind n -> (Type n -> Type n) -> Type n tForall k f = TForall (BAnon k) (f (TVar (UIx 0))) -- | Build an anonymous type abstraction, with a single parameter. -- Starting the next index from the given value. tForall' :: Int -> Kind n -> (Type n -> Type n) -> Type n tForall' ix k f = TForall (BAnon k) (f (TVar (UIx ix))) -- | Build an anonymous type abstraction, with several parameters. -- Starting the next index from the given value. tForalls :: [Kind n] -> ([Type n] -> Type n) -> Type n tForalls ks f = let bs = [BAnon k | k <- ks] us = map (\i -> TVar (UIx i)) [0 .. (length ks - 1)] in foldr TForall (f $ reverse us) bs -- | Build an anonymous type abstraction, with several parameters. -- Starting the next index from the given value. tForalls' :: Int -> [Kind n] -> ([Type n] -> Type n) -> Type n tForalls' ix ks f = let bs = [BAnon k | k <- ks] us = map (\i -> TVar (UIx i)) [ix .. ix + (length ks - 1)] in foldr TForall (f $ reverse us) bs -- | Split nested foralls from the front of a type, -- or `Nothing` if there was no outer forall. takeTForalls :: Type n -> Maybe ([Bind n], Type n) takeTForalls tt = let go bs (TForall b t) = go (b:bs) t go bs t = (reverse bs, t) in case go [] tt of ([], _) -> Nothing (bs, body) -> Just (bs, body) -- | Erase all `TForall` quantifiers from a type. eraseTForalls :: Ord n => Type n -> Type n eraseTForalls tt = case tt of TVar{} -> tt TCon{} -> tt TForall _ t -> eraseTForalls t TApp t1 t2 -> TApp (eraseTForalls t1) (eraseTForalls t2) TSum ts -> TSum $ Sum.fromList (Sum.kindOfSum ts) $ map eraseTForalls $ Sum.toList ts -- Sums ----------------------------------------------------------------------- tSum :: Ord n => Kind n -> [Type n] -> Type n tSum k ts = TSum (Sum.fromList k ts) -- Unit ----------------------------------------------------------------------- tUnit :: Type n tUnit = TCon (TyConSpec TcConUnit) -- Function Constructors ------------------------------------------------------ -- | Construct a kind function. kFun :: Kind n -> Kind n -> Kind n kFun k1 k2 = ((TCon $ TyConKind KiConFun)`TApp` k1) `TApp` k2 infixr `kFun` -- | Construct some kind functions. kFuns :: [Kind n] -> Kind n -> Kind n kFuns [] k1 = k1 kFuns (k:ks) k1 = k `kFun` kFuns ks k1 -- | Destruct a kind function takeKFun :: Kind n -> Maybe (Kind n, Kind n) takeKFun kk = case kk of TApp (TApp (TCon (TyConKind KiConFun)) k1) k2 -> Just (k1, k2) _ -> Nothing -- | Destruct a chain of kind functions into the arguments takeKFuns :: Kind n -> ([Kind n], Kind n) takeKFuns kk = case kk of TApp (TApp (TCon (TyConKind KiConFun)) k1) k2 | (ks, k2') <- takeKFuns k2 -> (k1 : ks, k2') _ -> ([], kk) -- | Like `takeKFuns`, but return argument and return kinds in the same list. takeKFuns' :: Kind n -> [Kind n] takeKFuns' kk | (ks, k1) <- takeKFuns kk = ks ++ [k1] -- | Take the result kind of a kind function, or return the same kind -- unharmed if it's not a kind function. takeResultKind :: Kind n -> Kind n takeResultKind kk = case kk of TApp (TApp (TCon (TyConKind KiConFun)) _) k2 -> takeResultKind k2 _ -> kk -- Function types ------------------------------------------------------------- -- | Construct a pure function type. tFun :: Type n -> Type n -> Type n tFun t1 t2 = (TCon $ TyConSpec TcConFun) `tApps` [t1, t2] infixr `tFun` -- | Construct a value type function, -- with the provided effect and closure. tFunEC :: Type n -> Effect n -> Closure n -> Type n -> Type n tFunEC t1 eff clo t2 = (TCon $ TyConSpec TcConFunEC) `tApps` [t1, eff, clo, t2] infixr `tFunEC` -- | Construct a pure and empty value type function. tFunPE :: Type n -> Type n -> Type n tFunPE t1 t2 = tFunEC t1 (tBot kEffect) (tBot kClosure) t2 infixr `tFunPE` -- | Construct a pure and empty function from a list containing the -- parameter and return type. Yields `Nothing` if the list is empty. tFunOfList :: [Type n] -> Maybe (Type n) tFunOfList ts = case reverse ts of [] -> Nothing (t : tsArgs) -> let tFuns' [] = t tFuns' (t' : ts') = t' `tFun` tFuns' ts' in Just $ tFuns' (reverse tsArgs) -- | Construct a pure and empty function from a list containing the -- parameter and return type. Yields `Nothing` if the list is empty. tFunOfListPE :: [Type n] -> Maybe (Type n) tFunOfListPE ts = case reverse ts of [] -> Nothing (t : tsArgs) -> let tFunPEs' [] = t tFunPEs' (t' : ts') = t' `tFunPE` tFunPEs' ts' in Just $ tFunPEs' (reverse tsArgs) -- | Yield the argument and result type of a function type. -- -- Works for both `TcConFun` and `TcConFunEC`. takeTFun :: Type n -> Maybe (Type n, Type n) takeTFun tt = case tt of TApp (TApp (TCon (TyConSpec TcConFun)) t1) t2 -> Just (t1, t2) TApp (TApp (TApp (TApp (TCon (TyConSpec TcConFunEC)) t1) _eff) _clo) t2 -> Just (t1, t2) _ -> Nothing -- | Yield the argument and result type of a function type. takeTFunEC :: Type n -> Maybe (Type n, Effect n, Closure n, Type n) takeTFunEC tt = case tt of TApp (TApp (TApp (TApp (TCon (TyConSpec TcConFunEC)) t1) eff) clo) t2 -> Just (t1, eff, clo, t2) _ -> Nothing -- | Destruct the type of a function, returning just the argument and result types. -- -- Works for both `TcConFun` and `TcConFunEC`. takeTFunArgResult :: Type n -> ([Type n], Type n) takeTFunArgResult tt = case tt of TApp (TApp (TCon (TyConSpec TcConFun)) t1) t2 -> let (tsMore, tResult) = takeTFunArgResult t2 in (t1 : tsMore, tResult) TApp (TApp (TApp (TApp (TCon (TyConSpec TcConFunEC)) t1) _eff) _clo) t2 -> let (tsMore, tResult) = takeTFunArgResult t2 in (t1 : tsMore, tResult) _ -> ([], tt) -- | Destruct the type of a function, -- returning the witness argument, value argument and result types. -- The function type must have the witness implications before -- the value arguments, eg @T1 => T2 -> T3 -> T4 -> T5@. -- -- Works for both `TcConFun` and `TcConFunEC`. -- takeTFunWitArgResult :: Type n -> ([Type n], [Type n], Type n) takeTFunWitArgResult tt = case tt of TApp (TApp (TCon (TyConWitness TwConImpl)) t1) t2 -> let (twsMore, tvsMore, tResult) = takeTFunWitArgResult t2 in (t1 : twsMore, tvsMore, tResult) _ -> let (tvsMore, tResult) = takeTFunArgResult tt in ([], tvsMore, tResult) -- | Destruct the type of a possibly polymorphic function -- returning all kinds of quantifiers, witness arguments, -- and value arguments in the order they appear, along with -- the type of the result. takeTFunAllArgResult :: Type n -> ([Type n], Type n) takeTFunAllArgResult tt = case tt of TVar{} -> ([], tt) TCon{} -> ([], tt) TForall b t -> let (tsMore, tResult) = takeTFunAllArgResult t in (typeOfBind b : tsMore, tResult) TApp (TApp (TCon (TyConSpec TcConFun)) t1) t2 -> let (tsMore, tResult) = takeTFunAllArgResult t2 in (t1 : tsMore, tResult) TApp (TApp (TApp (TApp (TCon (TyConSpec TcConFunEC)) t1) _eff) _clo) t2 -> let (tsMore, tResult) = takeTFunAllArgResult t2 in (t1 : tsMore, tResult) TApp (TApp (TCon (TyConWitness TwConImpl)) t1) t2 -> let (tsMore, tResult) = takeTFunAllArgResult t2 in (t1 : tsMore, tResult) _ -> ([], tt) -- | Determine the arity of an expression by looking at its type. -- Count all the function arrows, and foralls. -- -- This assumes the type is in prenex form, meaning that all the quantifiers -- are at the front. arityOfType :: Type n -> Int arityOfType tt = case tt of TForall _ t -> 1 + arityOfType t t -> length $ fst $ takeTFunArgResult t -- Implications --------------------------------------------------------------- -- | Construct a witness implication type. tImpl :: Type n -> Type n -> Type n tImpl t1 t2 = ((TCon $ TyConWitness TwConImpl) `tApp` t1) `tApp` t2 infixr `tImpl` -- Suspensions ---------------------------------------------------------------- tSusp :: Effect n -> Type n -> Type n tSusp tE tA = (TCon $ TyConSpec TcConSusp) `tApp` tE `tApp` tA -- Level 3 constructors (sorts) ----------------------------------------------- sComp = TCon $ TyConSort SoConComp sProp = TCon $ TyConSort SoConProp -- Level 2 constructors (kinds) ----------------------------------------------- kData = TCon $ TyConKind KiConData kRegion = TCon $ TyConKind KiConRegion kEffect = TCon $ TyConKind KiConEffect kClosure = TCon $ TyConKind KiConClosure kWitness = TCon $ TyConKind KiConWitness -- Level 1 constructors (witness and computation types) ----------------------- -- Effect type constructors tRead = tcCon1 TcConRead tHeadRead = tcCon1 TcConHeadRead tDeepRead = tcCon1 TcConDeepRead tWrite = tcCon1 TcConWrite tDeepWrite = tcCon1 TcConDeepWrite tAlloc = tcCon1 TcConAlloc tDeepAlloc = tcCon1 TcConDeepAlloc -- Closure type constructors. tUse = tcCon1 TcConUse tDeepUse = tcCon1 TcConDeepUse -- Witness type constructors. tPure = twCon1 TwConPure tEmpty = twCon1 TwConEmpty tGlobal = twCon1 TwConGlobal tDeepGlobal = twCon1 TwConDeepGlobal tConst = twCon1 TwConConst tDeepConst = twCon1 TwConDeepConst tMutable = twCon1 TwConMutable tDeepMutable = twCon1 TwConDeepMutable tDistinct n = twCon2 (TwConDistinct n) tLazy = twCon1 TwConLazy tHeadLazy = twCon1 TwConHeadLazy tManifest = twCon1 TwConManifest tcCon1 tc t = (TCon $ TyConSpec tc) `tApp` t twCon1 tc t = (TCon $ TyConWitness tc) `tApp` t twCon2 tc ts = tApps (TCon $ TyConWitness tc) ts -- | Build a nullary type constructor of the given kind. tConData0 :: n -> Kind n -> Type n tConData0 n k = TCon (TyConBound (UName n) k) -- | Build a type constructor application of one argumnet. tConData1 :: n -> Kind n -> Type n -> Type n tConData1 n k t1 = TApp (TCon (TyConBound (UName n) k)) t1