TraceTransform

Method

Captures each intermediate step of a cascading or recursive transformation, returning a list of strings for debugging and analysis.

Product: 

Class: 

Warning

uCalc API Preview Release Notice:The uCalc engine has successfully transitioned to modern cross-platform environments.The next phase envolves some structural changes, performance optimizations, and API refinements.The API is subject to breaking changes prior to the stable release. Please evaluate the preview version thoroughly before production use.

Syntax

TraceTransform(string, string, string, string, string, string)

Parameters

expressionString
string
The expression string to transform and trace.
separator
string
(Default = "")
String that separates each element
format
string
(Default = "")
Expression used to format each element
elementVarName
string
(Default = "x")
Name of element variable in the format representing each element
indexVarName
string
(Default = "Index")
Name of index variable in the format representing each element
stepCountVarName
string
(Default = "Count")
Name of step count variable in the format representing each element

Return

String

A uCalc.String object that acts as a list. Each item in the list is a string representing one step in the transformation process.

Remarks

The TraceTransform method is a powerful debugging and introspection tool that executes a transformation and returns a complete history of every intermediate step. It is particularly useful for understanding how rules with the RewindOnChange property create cascading or recursive transformations.

How It Works

Instead of returning just the final transformed string, TraceTransform captures the state of the string after each successful rule application. It returns a uCalc.String object that acts as a list, where each item in the list is a snapshot of the string at one point in the transformation sequence.

This is invaluable for debugging complex rule sets where the output of one rule becomes the input for another.

Handling the Result: A List-like uCalc.String

The returned uCalc.String object is a collection of strings. You can format its output using its list-formatting methods before retrieving the final text:

  • ListSeparator(): Sets the separator string to be inserted between each step (e.g., a newline "{@nl}").
  • ListFunction(): Sets an expression used to format the elements. +++ ToDo: Merge ListFunction & ListFormat
  • ListFormat(): Provides advanced control over the output, allowing you to define prefixes, postfixes, and a custom formatting expression for each step.
  • Iteration: You can iterate through the returned object to process each step individually.

Optional arguments can be passed directly to TraceTransform to add a separator and for formatting.

💡 Why uCalc? (Comparative Analysis)

Without TraceTransform, debugging a multi-step transformation is a manual, imperative process:

  • Manual Logging: You would have to insert logging statements or set breakpoints inside your application's logic to see how the string changes after each pass of a while loop that simulates a recursive transform.
  • Step-Through Debugging: While possible, it can be difficult to visualize the overall flow and see all intermediate states at once.

TraceTransform provides a declarative and integrated solution. It's a built-in feature of the engine that captures the entire history of a transformation automatically. This allows you to get a complete, high-level overview of the process in a single call, making it significantly easier to diagnose complex rule interactions, identify infinite loops, and verify that a transformation is behaving as expected.

Examples

A simple cascading transformation (`A` -> `B` -> `C` -> `D`) shows the step-by-step output with configurable separator

ID: 1462

				
					using uCalcSoftware;

var uc = new uCalc();
var t = new uCalc.Transformer();
// RewindOnChange is necessary for cascading rules to be re-evaluated.
t.FromTo("A", "B").RewindOnChange = true;
t.FromTo("B", "C").RewindOnChange = true;
t.FromTo("C", "D").RewindOnChange = true;

// Trace the transformation of "A"
Console.WriteLine(t.TraceTransform("A", " -> "));
				
			
A -> B -> C -> D
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uCalc::Transformer t;
   // RewindOnChange is necessary for cascading rules to be re-evaluated.
   t.FromTo("A", "B").RewindOnChange(true);
   t.FromTo("B", "C").RewindOnChange(true);
   t.FromTo("C", "D").RewindOnChange(true);

   // Trace the transformation of "A"
   cout << t.TraceTransform("A", " -> ") << endl;
}
				
			
A -> B -> C -> D
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t As New uCalc.Transformer()
      '// RewindOnChange is necessary for cascading rules to be re-evaluated.
      t.FromTo("A", "B").RewindOnChange = true
      t.FromTo("B", "C").RewindOnChange = true
      t.FromTo("C", "D").RewindOnChange = true
      
      '// Trace the transformation of "A"
      Console.WriteLine(t.TraceTransform("A", " -> "))
   End Sub
End Module
				
			
A -> B -> C -> D
A simple cascading transformation (`A` -> `B` -> `C` -> `D`) shows the step-by-step output using ListSeparator()

ID: 1138

				
					using uCalcSoftware;

var uc = new uCalc();
var t = new uCalc.Transformer();
// RewindOnChange is necessary for cascading rules to be re-evaluated.
t.FromTo("A", "B").RewindOnChange = true;
t.FromTo("B", "C").RewindOnChange = true;
t.FromTo("C", "D").RewindOnChange = true;

// Trace the transformation of "A"
uCalc.String trace = t.TraceTransform("A");

// Format the output list with ' -> ' for readability
trace.ListSeparator(" -> ");

Console.WriteLine(trace);
				
			
A -> B -> C -> D
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uCalc::Transformer t;
   // RewindOnChange is necessary for cascading rules to be re-evaluated.
   t.FromTo("A", "B").RewindOnChange(true);
   t.FromTo("B", "C").RewindOnChange(true);
   t.FromTo("C", "D").RewindOnChange(true);

   // Trace the transformation of "A"
   uCalc::String trace = t.TraceTransform("A");

   // Format the output list with ' -> ' for readability
   trace.ListSeparator(" -> ");

   cout << trace << endl;
}
				
			
A -> B -> C -> D
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t As New uCalc.Transformer()
      '// RewindOnChange is necessary for cascading rules to be re-evaluated.
      t.FromTo("A", "B").RewindOnChange = true
      t.FromTo("B", "C").RewindOnChange = true
      t.FromTo("C", "D").RewindOnChange = true
      
      '// Trace the transformation of "A"
      Dim trace As uCalc.String = t.TraceTransform("A")
      
      '// Format the output list with ' -> ' for readability
      trace.ListSeparator(" -> ")
      
      Console.WriteLine(trace)
   End Sub
End Module
				
			
A -> B -> C -> D
Practical: Traces the recursive expansion of a custom `MySum` function, showing how it is broken down into a standard arithmetic expression.

ID: 1139

				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.ExpressionTransformer;

// Assume these rules are pre-defined to create a recursive sum
t.FromTo("MySum({x})", "{x}");
t.FromTo("MySum({x}, {y})", "({x} + MySum({y}))").RewindOnChange = true;

uCalc.String trace = t.TraceTransform("MySum(1,2,3,4)");
trace.ListSeparator("\n");

Console.WriteLine(trace);
				
			
MySum(1,2,3,4)
(1 + MySum(2,3,4))
(1 + (2 + MySum(3,4)))
(1 + (2 + (3 + MySum(4))))
(1 + (2 + (3 + 4)))
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.ExpressionTransformer();

   // Assume these rules are pre-defined to create a recursive sum
   t.FromTo("MySum({x})", "{x}");
   t.FromTo("MySum({x}, {y})", "({x} + MySum({y}))").RewindOnChange(true);

   uCalc::String trace = t.TraceTransform("MySum(1,2,3,4)");
   trace.ListSeparator("\n");

   cout << trace << endl;
}
				
			
MySum(1,2,3,4)
(1 + MySum(2,3,4))
(1 + (2 + MySum(3,4)))
(1 + (2 + (3 + MySum(4))))
(1 + (2 + (3 + 4)))
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.ExpressionTransformer
      
      '// Assume these rules are pre-defined to create a recursive sum
      t.FromTo("MySum({x})", "{x}")
      t.FromTo("MySum({x}, {y})", "({x} + MySum({y}))").RewindOnChange = true
      
      Dim trace As uCalc.String = t.TraceTransform("MySum(1,2,3,4)")
      trace.ListSeparator(vbCrLf)
      
      Console.WriteLine(trace)
   End Sub
End Module
				
			
MySum(1,2,3,4)
(1 + MySum(2,3,4))
(1 + (2 + MySum(3,4)))
(1 + (2 + (3 + MySum(4))))
(1 + (2 + (3 + 4)))
Demonstration of TraceTrancform, ListFunction, and IndexBase

ID: 147

				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();
t.DefaultRuleSet.RewindOnChange = true;
t.FromTo("AddUp({x})", "{x}");
t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");

Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index}: {x}\n'"));

// 0 is the default IndexBase.  Here we will use 1 instead.
// So it will now start with "Step: 1" instead of "Step: 0"
Console.WriteLine("--- Now with IndexBase = 1 ---");
Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index} of {Count}: {x}\n'").IndexBase(1));
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();
   t.DefaultRuleSet().RewindOnChange(true);
   t.FromTo("AddUp({x})", "{x}");
   t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");

   cout << t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index}: {x}\n'") << endl;

   // 0 is the default IndexBase.  Here we will use 1 instead.
   // So it will now start with "Step: 1" instead of "Step: 0"
   cout << "--- Now with IndexBase = 1 ---" << endl;
   cout << t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index} of {Count}: {x}\n'").IndexBase(1) << endl;
}
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      t.DefaultRuleSet.RewindOnChange = true
      t.FromTo("AddUp({x})", "{x}")
      t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))")
      
      Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index}: {x}"+vbCrLf+"'"))
      
      '// 0 is the default IndexBase.  Here we will use 1 instead.
      '// So it will now start with "Step: 1" instead of "Step: 0"
      Console.WriteLine("--- Now with IndexBase = 1 ---")
      Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)").ListFunction("$'Step {Index} of {Count}: {x}"+vbCrLf+"'").IndexBase(1))
   End Sub
End Module
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
Demonstration of TraceTrancform with formatting argument and IndexBase

ID: 1464

				
					using uCalcSoftware;

var uc = new uCalc();
var t = uc.NewTransformer();
t.DefaultRuleSet.RewindOnChange = true;
t.FromTo("AddUp({x})", "{x}");
t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");

Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index}: {x}\n'"));

// 0 is the default IndexBase.  Now we use 1 instead.
// So it will now start with "Step: 1" instead of "Step: 0"
Console.WriteLine("--- Now with IndexBase = 1 ---");
Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index} of {Count}: {x}\n'").IndexBase(1));
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   auto t = uc.NewTransformer();
   t.DefaultRuleSet().RewindOnChange(true);
   t.FromTo("AddUp({x})", "{x}");
   t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))");

   cout << t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index}: {x}\n'") << endl;

   // 0 is the default IndexBase.  Now we use 1 instead.
   // So it will now start with "Step: 1" instead of "Step: 0"
   cout << "--- Now with IndexBase = 1 ---" << endl;
   cout << t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index} of {Count}: {x}\n'").IndexBase(1) << endl;
}
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t = uc.NewTransformer()
      t.DefaultRuleSet.RewindOnChange = true
      t.FromTo("AddUp({x})", "{x}")
      t.FromTo("AddUp({x}, {y})", "({x} + AddUp({y}))")
      
      Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index}: {x}"+vbCrLf+"'"))
      
      '// 0 is the default IndexBase.  Now we use 1 instead.
      '// So it will now start with "Step: 1" instead of "Step: 0"
      Console.WriteLine("--- Now with IndexBase = 1 ---")
      Console.WriteLine(t.TraceTransform("AddUp(1, 2, 3, 4)", "", "$'Step {Index} of {Count}: {x}"+vbCrLf+"'").IndexBase(1))
   End Sub
End Module
				
			
Step 0: AddUp(1, 2, 3, 4)
Step 1: (1 + AddUp(2, 3, 4))
Step 2: (1 + (2 + AddUp(3, 4)))
Step 3: (1 + (2 + (3 + AddUp(4))))
Step 4: (1 + (2 + (3 + 4)))

--- Now with IndexBase = 1 ---
Step 1 of 5: AddUp(1, 2, 3, 4)
Step 2 of 5: (1 + AddUp(2, 3, 4))
Step 3 of 5: (1 + (2 + AddUp(3, 4)))
Step 4 of 5: (1 + (2 + (3 + AddUp(4))))
Step 5 of 5: (1 + (2 + (3 + 4)))
Internal Test: Verifies advanced formatting of the trace output using `ListFormat` to create a custom, detailed step-by-step log.

ID: 1140

				
					using uCalcSoftware;

var uc = new uCalc();
var t = new uCalc.Transformer();
t.FromTo("A", "B").RewindOnChange = true;
t.FromTo("B", "C").RewindOnChange = true;
t.FromTo("C", "D").RewindOnChange = true;

uCalc.String trace = t.TraceTransform("A");

// Apply a custom format to each step in the list
trace.ListFormat("!", "(", ")", "$'{txt}->{n+1}/{c}'", "txt", "n", "c");

Console.WriteLine(trace);
				
			
(A->1/4!B->2/4!C->3/4!D->4/4)
				
					#include <iostream>
#include "uCalc.h"

using namespace std;
using namespace uCalcSoftware;

int main() {
   uCalc uc;
   uCalc::Transformer t;
   t.FromTo("A", "B").RewindOnChange(true);
   t.FromTo("B", "C").RewindOnChange(true);
   t.FromTo("C", "D").RewindOnChange(true);

   uCalc::String trace = t.TraceTransform("A");

   // Apply a custom format to each step in the list
   trace.ListFormat("!", "(", ")", "$'{txt}->{n+1}/{c}'", "txt", "n", "c");

   cout << trace << endl;
}
				
			
(A->1/4!B->2/4!C->3/4!D->4/4)
				
					Imports System
Imports uCalcSoftware
Public Module Program
   Public Sub Main()
      Dim uc As New uCalc()
      Dim t As New uCalc.Transformer()
      t.FromTo("A", "B").RewindOnChange = true
      t.FromTo("B", "C").RewindOnChange = true
      t.FromTo("C", "D").RewindOnChange = true
      
      Dim trace As uCalc.String = t.TraceTransform("A")
      
      '// Apply a custom format to each step in the list
      trace.ListFormat("!", "(", ")", "$'{txt}->{n+1}/{c}'", "txt", "n", "c")
      
      Console.WriteLine(trace)
   End Sub
End Module
				
			
(A->1/4!B->2/4!C->3/4!D->4/4)

This page last modified on: 

8/28/2026