diff --git a/ASTPlayground/MainForm.pas b/ASTPlayground/MainForm.pas index 992bc20..adfcc17 100644 --- a/ASTPlayground/MainForm.pas +++ b/ASTPlayground/MainForm.pas @@ -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.FunctionCall( - TAst.Identifier('fib_iter'), - [TAst.Identifier('n'), TAst.Constant(TScalar.FromInt64(0)), TAst.Constant(TScalar.FromInt64(1))] + 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'), + [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))]) ] );