| Safe Haskell | Safe |
|---|---|
| Language | Haskell2010 |
ReWire.Eidos.Simplify
Description
The Eidos simplifier: occurrence-driven, let-preserving partial
evaluation (the retired reduce/specialize/purge loop's successor,
doc/eidos.md §8). simplify repeats specialize-on-values, purge, and
reduce until every definition is synthable and dictionary-free,
bounded by --depth with the retired loop's diagnostic.
reduceExpis let-preserving: beta redexes become lets, and a let is inlined only when its binder is dead, used once, bound to an atom, or dictionary-typed (dictTyCons— never representable, so substituted at every occurrence); a representable multi-use binding KEEPS its let (sharing). The one lambda-lifting policy surviving from the retired pipeline is explicit here (Clash's LiftNonRep): a multi-use *function-typed* let cannot stay (it is not representable), so it is lifted to a top-level definition over its captured locals, named with the$LL.compiler-lifted prefix (display-only: the machine fold strips it when naming the Hyle definition). Top-level references are never unfolded — the function hierarchy is preserved; higher-orderness dies by argument baking, not call inlining.specializeon values (the retired value-argument specializer): a call to a top-level definition with *closed* arguments (free variables all top-level) bakes those arguments into a memoized clone named from the baked-argument canon (originTag). Self-calls in the clone still reference the origin — the memo closes recursive loops. Memo keys are alpha-canonical: arguments are renumbered from a disjoint unique supply and printed. Baking is also how non-representable scalar arguments (Integer, String) disappear: their call sites pass closed values.purge: definitions unreachable from the device root (plus the builtin signature carriers, which carry the builtins' type assumptions to the Eidos-to-Hyle fold).
Join points are preserved (dead ones are dropped); datatypes are left untouched.
Synopsis
- simplify :: MonadError AstError m => Natural -> Program -> m Program
- purge :: Program -> Program
- reduceProgram :: forall (m :: Type -> Type). MonadError AstError m => Program -> SimpT m Program
- reduceExp :: forall (m :: Type -> Type). MonadError AstError m => IntSet -> HashSet Text -> Exp -> SimpT m Exp
- dictTyCons :: [DataDefn] -> HashSet Text
- type SimpT (m :: Type -> Type) = StateT SimpSt m
- runSimpT :: Monad m => Program -> SimpT m a -> m a
Documentation
simplify :: MonadError AstError m => Natural -> Program -> m Program Source #
Partial evaluation to the synthable, dictionary-free fixpoint, bounded by the given depth.
purge :: Program -> Program Source #
Definitions transitively reachable from the device root and the builtin signature carriers. Datatypes are left untouched.
reduceProgram :: forall (m :: Type -> Type). MonadError AstError m => Program -> SimpT m Program Source #
reduceExp :: forall (m :: Type -> Type). MonadError AstError m => IntSet -> HashSet Text -> Exp -> SimpT m Exp Source #
One bottom-up reduction pass over an expression: beta redexes become
lets; lets inline when dead, single-use, or atom-bound; multi-use
function-typed lets are lifted to top level (LiftNonRep); known-
constructor and known-literal cases select their alternative; lambdas
eta-reduce; dead join points drop. Top-level references are never
unfolded. The first argument is the set of top-level uniques (a
lift's captures are the free variables outside it); the second is the
dictionary-datatype names (dictTyCons): a dictionary-typed binding
is substituted at every occurrence rather than shared, because it can
never be represented -- multi-use superclass projections would
otherwise never see the constructor.
dictTyCons :: [DataDefn] -> HashSet Text Source #
Names of the datatypes with a function-typed constructor field (class dictionaries and their shapes): a value of such a type can never reach Hyle, so bindings of these types must always reduce away.