eval lambda block: bubble up substitutions

This commit is contained in:
Joeri Exelmans 2025-05-17 12:06:27 +02:00
parent 496463bbac
commit 51ff4d24b0
3 changed files with 23 additions and 15 deletions

View file

@ -1,5 +1,9 @@
.lambdaExpr { .lambdaBlock {
display: inline-block; display: inline-block;
border: solid 1px darkgrey; border: solid 1px darkgrey;
margin: 2px; margin: 2px;
} }
.lambdaInner {
display: inline-block;
}

View file

@ -56,7 +56,7 @@ export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockPr
t: getUnusedTypeVar(env), t: getUnusedTypeVar(env),
}); });
return <span> return <span className="lambdaBlock">
<span className="keyword">&#955;</span> <span className="keyword">&#955;</span>
&nbsp; &nbsp;
<span className="lambdaInputParam"> <span className="lambdaInputParam">
@ -72,7 +72,7 @@ export function LambdaBlock({state, setState, suggestionPriority}: LambdaBlockPr
&nbsp; &nbsp;
<span className="keyword">:</span> <span className="keyword">:</span>
&nbsp; &nbsp;
<div className="lambdaExpr"> <div className="lambdaInner">
<EnvContext value={innerEnv}> <EnvContext value={innerEnv}>
<Editor <Editor
state={state.expr} state={state.expr}

View file

@ -99,6 +99,9 @@ export function evalCallBlock2(fnResolved: ResolvedType, inputResolved: Resolved
// fn is a function... // fn is a function...
const [outType, substitutions] = assignFnSubstitutions(fnResolved.t, inputResolved.t); // may throw const [outType, substitutions] = assignFnSubstitutions(fnResolved.t, inputResolved.t); // may throw
// console.log('assignFn...', prettyT(fnResolved.t), prettyT(inputResolved.t), '\nout =', prettyT(outType), substitutions);
const mergedSubstitutions = mergeMaps(substitutions, fnResolved.substitutions, inputResolved.substitutions); const mergedSubstitutions = mergeMaps(substitutions, fnResolved.substitutions, inputResolved.substitutions);
if (inputResolved.kind === "error") { if (inputResolved.kind === "error") {
@ -177,11 +180,21 @@ export function getUnusedTypeVar(env) {
export function evalLambdaBlock(paramName: string, expr: EditorState, env): ResolvedType { export function evalLambdaBlock(paramName: string, expr: EditorState, env): ResolvedType {
const paramType = getUnusedTypeVar(env); const paramType = getUnusedTypeVar(env);
// static env: we only know the name and the type
const staticInnerEnv = makeInnerEnv(env, paramName, {
kind: "unknown", // parameter value is not statically known
t: paramType,
substitutions: new Map(),
});
const exprResolved = evalEditorBlock(expr, staticInnerEnv);
const lambdaT = fnType(_ => paramType)(_ => exprResolved.t);
const lambdaTSubstituted = substitute(lambdaT, exprResolved.substitutions, []);
const paramTypeSubstituted = lambdaTSubstituted.params[0](lambdaTSubstituted);
const fn = (x: any) => { const fn = (x: any) => {
const innerEnv = makeInnerEnv(env, paramName, { const innerEnv = makeInnerEnv(env, paramName, {
kind: "value", kind: "value",
i: x, i: x,
t: paramType, t: paramTypeSubstituted,
substitutions: new Map(), substitutions: new Map(),
}); });
const result = evalEditorBlock(expr, innerEnv); const result = evalEditorBlock(expr, innerEnv);
@ -189,20 +202,11 @@ export function evalLambdaBlock(paramName: string, expr: EditorState, env): Reso
return result.i; return result.i;
} }
} }
// static env: we only know the name and the type
const staticInnerEnv = makeInnerEnv(env, paramName, {
kind: "unknown", // parameter value is not statically known
t: paramType,
substitutions: new Map(),
});
const abstractOutput = evalEditorBlock(expr, staticInnerEnv);
const t = fnType(_ => paramType)(_ => abstractOutput.t);
const T = substitute(t, abstractOutput.substitutions, [])
return { return {
kind: "value", kind: "value",
t: T, t: lambdaTSubstituted,
i: fn, i: fn,
substitutions: new Map(), substitutions: exprResolved.substitutions,
}; };
} }