Lambda's Factory #
This module formalizes Lambda's factory, which is a mechanism to extend the
type checker (see Strata.DL.Lambda.LExprT) and partial evaluator (see
Strata.DL.Lambda.LExprEval) by providing a map from operations to their types
and optionally, denotations. The factory allows adding type checking and
evaluation support for new operations without modifying the implementation of
either or any core ASTs.
Also see Strata.DL.Lambda.IntBoolFactory for a concrete example of a factory.
A signature is a map from variable identifiers to types.
Equations
- Lambda.Signature IDMeta Ty = ListMap (Lambda.Identifier IDMeta) Ty
Instances For
Equations
- Lambda.Signature.format [] = Std.Format.text ""
- Lambda.Signature.format [(k, v)] = Std.format "(" ++ Std.format k ++ Std.format " : " ++ Std.format v ++ Std.format ")"
- Lambda.Signature.format ((k, v) :: rest) = Std.format "(" ++ Std.format k ++ Std.format " : " ++ Std.format v ++ Std.format ") " ++ Lambda.Signature.format rest
Instances For
Equations
Instances For
Equations
Instances For
A concrete evaluator for a factory function (see LFunc.concreteEval). It takes
the metadata to attach to the result, the type annotation of the function's
operator at the call (none when the operator is not annotated), and the
arguments of the call. It returns the result of the call, or none when it does
not apply (e.g. the arguments are not literals). The operator's type gives the
evaluator the instantiation of the function's type parameters, which it needs to
build a literal of a type that is not determined by the arguments (e.g. the empty
sequence).
The soundness obligations on an evaluator (LFunc.InterpConsistentEval,
Factory.EvalWellTyped, LFunc.EvalSound) constrain its result only when the
annotation is the function's type instantiated by the call's type substitution
(LFunc.instTy), which is the annotation of the operator of a well-typed call. No
theorem covers its result at other annotations: none, which LExpr.eval passes
for an unannotated operator and Core's model (gatherEval) always passes, or a type
with type variables. So an evaluator that reads the annotation returns none
unless the annotation is a ground type; an evaluator that ignores the annotation is
covered at every annotation.
Equations
- Lambda.ConcreteEval T = (T.Metadata → Option Lambda.LMonoTy → List (Lambda.LExpr T.mono) → Option (Lambda.LExpr T.mono))
Instances For
The type annotation of an operator, and none for any other expression.
Instances For
The AST-facing Lambda function structure - instantiation of the base Func for
Lambda expressions. It is used for functions that appear in the Strata AST
(e.g. Core.Function), and carries only plain data — the base
Func excludes the function-typed concreteEval, so it has decidable equality.
Universally quantified type identifiers, if any, appear before this signature and can quantify over the type identifiers in it.
Equations
Instances For
A Lambda factory function - the full, evaluator/factory-facing function
structure. It extends the AST-facing Func with the partial-evaluator hook
concreteEval. All other fields live on the base Func.
A optional evaluation function can be provided in the concreteEval field for
each factory function to allow the partial evaluator to do constant propagation
when all the arguments of a function are concrete; its type is ConcreteEval.
Here's an example of a concreteEval function for Int.Add:
(fun md _ args => match args with
| [e1, e2] =>
match LExpr.denoteInt e1, LExpr.denoteInt e2 with
| some x, some y => some (.intConst md (x + y))
| _, _ => none
| _ => none)
Note that if there is an arity mismatch or if the arguments are not concrete/constants, this fails and it returns .none. If LFunc already has body, it must not have concreteEval, and vice versa.
- mk' :: (
- name : T.Identifier
- body : Option (Lambda.LExpr T.mono)
- axioms : List (Lambda.LExpr T.mono)
- preconditions : List (FuncPrecondition (Lambda.LExpr T.mono) T.Metadata)
- measure : Option (Lambda.LExpr T.mono)
- concreteEval : Option (ConcreteEval T)
- )
Instances For
The type of the function f instantiated by the type substitution S: the arrow from its
input types to its output type, each under S. The operator of a call of f well typed at
the instance S is annotated with it, and the soundness obligations on concrete evaluators
are stated at it (see ConcreteEval).
Equations
- f.instTy S = (Lambda.LMonoTy.subst S f.output).mkArrow' (List.map (Lambda.LMonoTy.subst S) (List.map Prod.snd f.inputs))
Instances For
Helper constructor for LFunc to maintain backward compatibility.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Lift an AST-facing LFuncDefined (base Func) into the full LFunc,
optionally attaching concreteEval at the evaluator boundary. All other
data carries over unchanged via toFunc.
Instances For
Equations
- Lambda.instInhabitedLFunc = { default := { name := default, inputs := [], output := Lambda.LMonoTy.bool } }
Equations
- Lambda.instToFormatLFuncOfLExpr = { format := fun (f : Lambda.LFunc T) => f.format }
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
Instances For
Equations
- f.inputPolyTypes = List.map (fun (x : T.Identifier × Lambda.LMonoTy) => match x with | (id, mty) => (id, Lambda.LTy.forAll f.typeArgs mty)) f.inputs
Instances For
Equations
- f.inputMonoSignature = List.map (fun (x : T.Identifier × Lambda.LMonoTy) => match x with | (id, mty) => (id, Lambda.LTy.forAll [] mty)) f.inputs
Instances For
Equations
Instances For
Equations
- One or more equations did not get rendered due to their size.
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
Instances For
Equations
- f.eraseTypes = { toFunc := Lambda.LFuncDefined.eraseTypes f.toFunc, concreteEval := f.concreteEval }
Instances For
The type checker and partial evaluator for Lambda is parameterizable by
a user-provided Factory.
We don't have any "built-in" functions like +, -, etc. in (LExpr IDMeta) -- lambdas are our only tool. Factory gives us a way to add
support for concrete/symbolic evaluation and type checking for FunFactory
functions without actually modifying any core logic or the ASTs.
The underlying array of factory functions.
- nameMap : Std.HashMap String Nat
Instances For
Equations
- f.mem name = (name ∈ Lambda.Factory.nameMap✝ f)
Instances For
Equations
- f.instMemDecidable name = inferInstance
Instances For
Equations
- Lambda.Factory.instMem = { mem := Lambda.Factory.mem }
Equations
- f.instMembershipDecidable name = f.instMemDecidable name
Instances For
Equations
- Lambda.Factory.instGetElem? = { getElem := Lambda.Factory.get, getElem? := Lambda.Factory.get? }
Equations
Instances For
Equations
- Lambda.Factory.instInhabited = { default := Lambda.Factory.default }
Equations
Instances For
Equations
- F.append a = Array.foldl Lambda.Factory.pushIfNew F a
Instances For
Equations
Instances For
Equations
- F.getFunctionNames = Array.map (fun (f : Lambda.LFunc T) => f.name) F.toArray
Instances For
Add a function func to the factory F. Redefinitions are not allowed.
Equations
- One or more equations did not get rendered due to their size.
Instances For
Append a factory newF to an existing factory F, checking for redefinitions
along the way.
Equations
- F.tryAddAll newF = Array.foldlM (fun (x1 : Lambda.Factory T) (x2 : Lambda.LFunc T) => x1.tryPush x2) F newF
Instances For
Append a factory newF to an existing factory F, checking for redefinitions
along the way.
Equations
- F.addFactory newF = F.tryAddAll newF.toArray
Instances For
Equations
Instances For
Equations
- Lambda.getLFuncCall.go (Lambda.LExpr.app m (Lambda.LExpr.app m_1 e' arg1) arg2) acc = Lambda.getLFuncCall.go e' ([arg1, arg2] ++ acc)
- Lambda.getLFuncCall.go (Lambda.LExpr.app m (Lambda.LExpr.op m_1 fn fnty) arg1) acc = (Lambda.LExpr.op m_1 fn fnty, [arg1] ++ acc)
- Lambda.getLFuncCall.go e acc = (e, acc)
Instances For
Equations
Instances For
If e is a call of a factory function, get the operator (.op), a list
of all the actuals, and the (LFunc IDMeta).
Equations
- One or more equations did not get rendered due to their size.