RECUR keyword added

This commit is contained in:
Michael Schimmel
2025-09-20 12:06:51 +02:00
parent e03155179a
commit 81dd69bf49
13 changed files with 352 additions and 98 deletions
+59 -90
View File
@@ -21,9 +21,6 @@ uses
FMX.ScrollBox,
FMX.Memo,
FMX.Controls.Presentation,
Myc.Fmx.AstEditor,
Myc.Fmx.AstEditor.Node,
Myc.Fmx.AstEditor.Workspace,
Myc.Data.Scalar,
Myc.Data.Value,
Myc.Ast.Nodes,
@@ -36,7 +33,10 @@ uses
Myc.Ast.RTL,
FMX.Layouts,
FMX.Objects,
Myc.Ast.Debugger;
Myc.Ast.Debugger,
Myc.Fmx.AstEditor,
Myc.Fmx.AstEditor.Node,
Myc.Fmx.AstEditor.Workspace;
type
// A test record
@@ -281,31 +281,42 @@ var
sw: TStopwatch;
begin
// Create a setup script to define a memoize-compatible 'fib' function globally.
// This is rewritten to be tail-recursive using the 'recur' keyword.
var fibAst :=
TAst.Block(
[
// 1. var fib; (Declare the name so it can be captured by the lambda. Initializer is nil)
// 1. var fib_iter = lambda(n, a, b) { ... }; (The tail-recursive part)
TAst.VarDecl(
TAst.Identifier('fib_iter'),
TAst.LambdaExpr(
[TAst.Identifier('n'), TAst.Identifier('a'), TAst.Identifier('b')],
TAst.TernaryExpr(
TAst.BinaryExpr(TAst.Identifier('n'), boEqual, TAst.Constant(TScalar.FromInt64(0))),
TAst.Identifier('a'), // Base case 1
TAst.TernaryExpr(
TAst.BinaryExpr(TAst.Identifier('n'), boEqual, TAst.Constant(TScalar.FromInt64(1))),
TAst.Identifier('b'), // Base case 2
TAst.Recur( // Tail-recursive step
[
TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1))),
TAst.Identifier('b'),
TAst.BinaryExpr(TAst.Identifier('a'), boAdd, TAst.Identifier('b'))
]
)
)
)
)
),
// 2. var fib;
TAst.VarDecl(TAst.Identifier('fib')),
// 2. var fib_impl = lambda(n) { ... fib(n-1) + fib(n-2) ... };
// 3. fib = lambda(n) { fib_iter(n, 0, 1) }; (The public-facing function)
TAst.Assign(
TAst.Identifier('fib'),
TAst.LambdaExpr(
[TAst.Identifier('n')],
TAst.TernaryExpr(
TAst.BinaryExpr(TAst.Identifier('n'), boLess, TAst.Constant(TScalar.FromInt64(2))),
TAst.Identifier('n'),
TAst.BinaryExpr(
// Recursive calls now use the re-bindable name 'fib' instead of 'Self'
TAst.FunctionCall(
TAst.Identifier('Self'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
),
boAdd,
TAst.FunctionCall(
TAst.Identifier('Self'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(2)))]
)
)
TAst.FunctionCall(
TAst.Identifier('fib_iter'),
[TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(0)), TAst.Constant(TScalar.FromInt64(1))]
)
)
)
@@ -314,10 +325,10 @@ begin
var fibScope := TAstBinder.Bind(fibAst, FGScope).CreateScope(FGScope);
var visitor := CreateVisitor(fibScope);
Result := visitor.Execute(fibAst);
visitor.Execute(fibAst);
Memo1.Lines.Clear;
Memo1.Lines.Add('--- Recursive fib with AST---');
Memo1.Lines.Add('--- Tail-Recursive fib with AST---');
sw := TStopwatch.StartNew;
root := TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(30))]);
@@ -330,7 +341,7 @@ begin
Memo1.Lines.Add(Format('Result: fib(30) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
Memo1.Lines.Add('');
Memo1.Lines.Add('--- Memoized recursive fib with AST (using global fib)---');
Memo1.Lines.Add('--- Memoized tail-recursive fib with AST (using global fib)---');
sw := TStopwatch.StartNew;
root :=
@@ -375,30 +386,39 @@ var
sw: TStopwatch;
begin
Memo1.Lines.Clear;
Memo1.Lines.Add('--- Recursive factorial(20) ---');
Memo1.Lines.Add('--- Tail-Recursive factorial(20) ---');
sw := TStopwatch.StartNew;
// Rewritten to be tail-recursive to use 'recur'
root :=
TAst.Block(
[
// Define the tail-recursive helper function
TAst.VarDecl(
TAst.Identifier('factorial'),
TAst.Identifier('fact_iter'),
TAst.LambdaExpr(
[TAst.Identifier('n')],
[TAst.Identifier('n'), TAst.Identifier('acc')],
TAst.TernaryExpr(
TAst.BinaryExpr(TAst.Identifier('n'), boLess, TAst.Constant(TScalar.FromInt64(2))),
TAst.Constant(TScalar.FromInt64(1)),
TAst.BinaryExpr(
TAst.Identifier('n'),
boMultiply,
TAst.FunctionCall(
TAst.Identifier('Self'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
)
TAst.BinaryExpr(TAst.Identifier('n'), boLessOrEqual, TAst.Constant(TScalar.FromInt64(1))),
TAst.Identifier('acc'), // Base case: return the accumulator
TAst.Recur( // Tail-recursive step
[
TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1))),
TAst.BinaryExpr(TAst.Identifier('acc'), boMultiply, TAst.Identifier('n'))
]
)
)
)
),
// Define the public-facing factorial function
TAst.VarDecl(
TAst.Identifier('factorial'),
TAst.LambdaExpr(
[TAst.Identifier('n')],
TAst.FunctionCall(TAst.Identifier('fact_iter'), [TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(1))])
)
),
// Call the main function
TAst.FunctionCall(TAst.Identifier('factorial'), [TAst.Constant(TScalar.FromInt64(20))])
]
);
@@ -566,54 +586,6 @@ begin
var setupAst :=
TAst.Block(
[
// TAst.VarDecl(
// TAst.Identifier('CreateSMA'),
// TAst.LambdaExpr(
// [TAst.Identifier('len')],
// TAst.Block(
// [
// TAst.VarDecl(TAst.Identifier('sum'), TAst.Constant(TScalar.FromDouble(0.0))),
// TAst.VarDecl(TAst.Identifier('count'), TAst.Constant(TScalar.FromInt64(0))),
// TAst.LambdaExpr(
// [TAst.Identifier('series'), TAst.Identifier('val')],
// TAst.Block(
// [
// TAst.Assign(
// TAst.Identifier('sum'),
// TAst.BinaryExpr(TAst.Identifier('sum'), boAdd, TAst.Identifier('val'))
// ),
// TAst.Assign(
// TAst.Identifier('count'),
// TAst.BinaryExpr(TAst.Identifier('count'), boAdd, TAst.Constant(TScalar.FromInt64(1)))
// ),
// TAst.IfExpr(
// TAst.BinaryExpr(TAst.Identifier('count'), boGreater, TAst.Identifier('len')),
// TAst.Assign(
// TAst.Identifier('sum'),
// TAst.BinaryExpr(
// TAst.Identifier('sum'),
// boSubtract,
// TAst.Indexer(TAst.Identifier('series'), TAst.Identifier('len'))
// )
// ),
// nil
// ),
// TAst.BinaryExpr(
// TAst.Identifier('sum'),
// boDivide,
// TAst.TernaryExpr(
// TAst.BinaryExpr(TAst.Identifier('count'), boLess, TAst.Identifier('len')),
// TAst.Identifier('count'),
// TAst.Identifier('len')
// )
// )
// ]
// )
// )
// ]
// )
// )
// ),
TAst.VarDecl(
TAst.Identifier('smaFast'),
TAst.FunctionCall(TAst.Identifier('CreateSMA'), [TAst.Constant(TScalar.FromInt64(smaFastLength))])
@@ -961,14 +933,11 @@ begin
TAst.Identifier('countDown'),
TAst.LambdaExpr(
[TAst.Identifier('n')],
// if (n > 0) then Self(n-1) else 'done'
// if (n > 0) then recur(n-1) else 'done'
TAst.IfExpr(
TAst.BinaryExpr(TAst.Identifier('n'), boGreater, TAst.Constant(TScalar.FromInt64(0))),
// This is the tail call position.
TAst.FunctionCall(
TAst.Identifier('Self'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
),
// This is the tail call position, now using recur.
TAst.Recur([TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]),
// Base case of the recursion
TAst.Constant(TScalar.FromString('done'))
)