RECUR keyword added

This commit is contained in:
Michael Schimmel
2025-09-20 12:23:37 +02:00
parent 81dd69bf49
commit 7621849bfb
+28 -35
View File
@@ -280,77 +280,70 @@ var
result: TDataValue;
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.
// This script defines a naive, slow recursive 'fib' function.
// The lambda captures its own name ('fib') from the parent scope to perform recursion.
var fibAst :=
TAst.Block(
[
// 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;
// 1. var fib; (Declare the name so it can be captured by the lambda)
TAst.VarDecl(TAst.Identifier('fib')),
// 3. fib = lambda(n) { fib_iter(n, 0, 1) }; (The public-facing function)
// 2. fib = lambda(n) { ... fib(n-1) + fib(n-2) ... };
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(
// Naive recursive call using the variable name 'fib'
TAst.FunctionCall(
TAst.Identifier('fib_iter'),
[TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(0)), TAst.Constant(TScalar.FromInt64(1))]
TAst.Identifier('fib'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(1)))]
),
boAdd,
// Second naive recursive call
TAst.FunctionCall(
TAst.Identifier('fib'),
[TAst.BinaryExpr(TAst.Identifier('n'), boSubtract, TAst.Constant(TScalar.FromInt64(2)))]
)
)
)
)
)
]
);
// Create a new scope and define the 'fib' function within it.
var fibScope := TAstBinder.Bind(fibAst, FGScope).CreateScope(FGScope);
var visitor := CreateVisitor(fibScope);
visitor.Execute(fibAst);
Memo1.Lines.Clear;
Memo1.Lines.Add('--- Tail-Recursive fib with AST---');
Memo1.Lines.Add('--- Naive recursive fib with AST---');
sw := TStopwatch.StartNew;
root := TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(30))]);
// The script to execute is just the call to the function.
root := TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(25))]);
FLastAst := root;
// Execute with fibScope as parent. The helper function handles debug/prod switching.
// Execute within the scope where 'fib' is defined.
result := ExecuteAst(root, fibScope);
sw.Stop;
Memo1.Lines.Add(Format('Result: fib(30) %s (calculated in %d ms)', [result.ToString, sw.ElapsedMilliseconds]));
Memo1.Lines.Add('');
Memo1.Lines.Add('--- Memoized tail-recursive fib with AST (using global fib)---');
Memo1.Lines.Add('--- Memoized naive fib with AST (using global fib)---');
sw := TStopwatch.StartNew;
root :=
TAst.Block(
[
// Create a memoized version by calling the RTL function on the global 'fib'
// Create a memoized version by calling the RTL function on 'fib'
TAst.Assign(TAst.Identifier('fib'), TAst.FunctionCall(TAst.Identifier('Memoize'), [TAst.Identifier('fib')])),
// Call the memoized function
TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(30))])
// Call the new, memoized function
TAst.FunctionCall(TAst.Identifier('fib'), [TAst.Constant(TScalar.FromInt64(25))])
]
);