I think that when inserting my main method GetTermValueplus a class StackFrameand a few helper methods ( Returnand Replace) there should be all I need for it to be concise, but first a few notes about the code:
An ILambdaValuerepresents the value, which is mainly the result of an evaluation ILambdaTerm, which is the analyzed lambda member.
A class AbstractionValueis ILambdaFunction(which in turn is ILambdaValue) that contains IAbstractionTerm(which is ILambdaTerm), which is called AbstractionTerm, which contains the parsing of the paragraph, and IScope<ILambdaValue>is called Scope, which represents the environment in which the abstraction value was created.
An IScopeis just a dictionary with string keys. InnerScopeis one IScopethat models lambda substitution by taking the parent region and dictionary and overwriting the parent region with the values in the dictionary.
public class StackFrame
{
public ILambdaTerm Term;
public IScope<ILambdaValue> Scope;
public List<ILambdaValue> Results = new List<ILambdaValue>();
public StackFrame() { }
public StackFrame(ILambdaTerm term, IScope<ILambdaValue> scope)
{
Term = term;
Scope = scope;
}
}
private static void Return(Stack<StackFrame> stack, ILambdaValue result)
{
stack.Pop();
stack.Peek().Results.Add(result);
}
private static void Replace(Stack<StackFrame> stack, StackFrame stackFrame)
{
stack.Pop();
stack.Push(stackFrame);
}
public static ILambdaValue GetTermValue(ILambdaTerm _term, IScope<ILambdaValue> _scope)
{
Stack<StackFrame> stack = new Stack<StackFrame>();
stack.Push(new StackFrame());
stack.Push(new StackFrame(_term, _scope));
while (stack.Count > 1)
{
var stackFrame = stack.Peek();
switch (stackFrame.Term.TermKind)
{
case LambdaTermType.String:
Return(stack, new StringValue(((ILiteralTerm<string>)stackFrame.Term).Value));
break;
case LambdaTermType.Number:
Return(stack, new NumberValue(((ILiteralTerm<double>)stackFrame.Term).Value));
break;
case LambdaTermType.Boolean:
Return(stack, new BooleanValue(((ILiteralTerm<bool>)stackFrame.Term).Value));
break;
case LambdaTermType.Variable:
Return(stack, stackFrame.Scope[((IVariableTerm)stackFrame.Term).Name]);
break;
case LambdaTermType.Application:
{
var application = (IApplicationTerm)stackFrame.Term;
if (stackFrame.Results.Count == 0)
{
stack.Push(new StackFrame(application.Function, stackFrame.Scope));
}
else if (stackFrame.Results.Count <= application.Arguments.Length)
{
stack.Push(new StackFrame(application.Arguments[stackFrame.Results.Count - 1], stackFrame.Scope));
}
else
{
var function = (ILambdaFunction)stackFrame.Results[0];
var argList = stackFrame.Results.Skip(1).ToList();
if (function is AbstractionValue)
{
var abstraction = (AbstractionValue)function;
var substitutions = abstraction.AbstractionTerm.Parameters.Select((Param, Index) => new { Param, Index }).ToDictionary(ai => ai.Param.Name, ai => argList[ai.Index]);
InnerScope<ILambdaValue> innerScope = new InnerScope<ILambdaValue>(abstraction.Scope, substitutions);
Replace(stack, new StackFrame(abstraction.AbstractionTerm.Body, innerScope));
}
else
{
Return(stack, function.ApplyTo(argList));
}
}
}
break;
case LambdaTermType.Abstraction:
Return(stack, new AbstractionValue((IAbstractionTerm)stackFrame.Term, stackFrame.Scope));
break;
default:
throw new NotImplementedException();
}
}
return stack.Peek().Results[0];
}
, , "" . ( , , , - , let overflow = \x.(overflow x) ( )) , , - , , . 100%, , , , . ( ) , , , ( "" ), , , .
, , - Replace if (function is AbstractionValue). -, , . ( , - , ).
, , ? , "" , ?