ddc-core-simpl-0.4.3.1: DDC/Core/Transform/Lambdas/Base.hs
module DDC.Core.Transform.Lambdas.Base
( S, evalState
, newVar
, newVarExtend
, Result (..)
, isLiftyContext)
where
import DDC.Core.Exp.Annot.Ctx
import DDC.Core.Exp.Annot
import DDC.Data.Name
import qualified Control.Monad.State.Strict as S
---------------------------------------------------------------------------------------------------
-- | State holding a variable name prefix and counter to
-- create fresh variable names.
type S = S.State (String, Int)
-- | Evaluate a desguaring computation,
-- using the given prefix for freshly introduced variables.
evalState :: String -> S a -> a
evalState n c
= S.evalState c (n, 0)
-- | Allocate a new named variable, yielding its associated bind and bound.
newVar
:: CompoundName n
=> String -- ^ Informational name to add.
-> Type n -- ^ Type of the new binder.
-> S (Bind n, Bound n)
newVar prefix t
= do (n, i) <- S.get
let name' = newVarName (n ++ "$" ++ prefix ++ "$" ++ show i)
S.put (n, i + 1)
return (BName name' t, UName name')
-- | Allocate a new named variable, yielding its associated bind and bound.
newVarExtend
:: CompoundName n
=> n -- ^ Base name.
-> String -- ^ Informational name to ad.
-> Type n -- ^ Type of the new binder.
-> S (Bind n, Bound n)
newVarExtend name prefix t
= do (n, i) <- S.get
let name' = extendName name (n ++ "$" ++ prefix ++ "$" ++ show i)
S.put (n, i + 1)
return (BName name' t, UName name')
---------------------------------------------------------------------------------------------------
-- | Result of lambda lifter recursion.
data Result a n
= Result
{ -- | Whether we've made any progress in this pass.
_resultProgress :: Bool
-- | Bindings that we've already lifted out,
-- and should be added at top-level.
, _resultBindings :: [(Bind n, Exp a n)]
}
instance Monoid (Result a n) where
mempty
= Result False []
mappend (Result p1 lts1) (Result p2 lts2)
= Result (p1 || p2) (lts1 ++ lts2)
---------------------------------------------------------------------------------------------------
-- | Check if this is a context that we should lift lambda abstractions out of.
isLiftyContext :: Ctx a n -> Bool
isLiftyContext ctx
= case ctx of
-- Don't lift out of the top-level context.
-- There's nowhere else to lift to.
CtxTop{} -> False
CtxLetLLet{} -> not $ isTopLetCtx ctx
CtxLetLRec{} -> not $ isTopLetCtx ctx
-- Don't lift if we're inside more lambdas.
-- We want to lift the whole binding group together.
CtxLAM{} -> False
CtxLam{} -> False
-- We can't do code generation for abstractions in these contexts,
-- so they need to be lifted.
CtxAppLeft{} -> True
CtxAppRight{} -> True
CtxLetBody{} -> True
CtxCaseScrut{} -> True
CtxCaseAlt{} -> True
CtxCastBody{} -> True