Papers
Topics
Authors
Recent
Search
2000 character limit reached

Reversible Recurrence Stack

Updated 4 July 2026
  • Reversible recurrence stack is a context data type that captures postponed recursive calls in invertible functions, enabling tail recursion transformation.
  • It orchestrates a forward tail-recursive accumulation of context frames and a backward unwind to reconstruct original inputs, ensuring bijective computation.
  • The approach is applied in reversible list reversal, language-level call-stack constructs, and processor architectures, offering efficient reversible computation.

Searching arXiv for papers on reversible recurrence stacks and related reversible recursion/stack models. A reversible recurrence stack is an explicit context data-type that converts invertible recursion into tail recursion by recording postponed recursive-call contexts as stack frames. In "Tail recursion transformation for invertible functions" (Kristensen et al., 2023), the construction is introduced for invertible functions under the observation that relaxing local reversibility to global invertibility drastically improves the situation for tail-recursion conversion. In related work, the same general concern—preserving information while unfolding and unwinding recursion—appears as a reversible producer/classical consumer split (Matos et al., 2021), as call-stack manipulation in the S-CORE\textsf{S-CORE} R-semantics\textsf{R-semantics} (Palazzo et al., 9 Jan 2025), and as a fully reversible call/return stack in the ReveR processor model (Vlasov, 2011).

1. Formal setting and the context data-type

The canonical formulation starts from an invertible function

f:ABf : A \to B

defined by a finite set of non-overlapping equations of two forms (Kristensen et al., 2023). Base clauses have the form

f(pk)=tkf(p_k) = t_k

for kKk \in K, where pkp_k is a linear pattern of type AA and tkt_k is a closed term of type BB with no recursive calls. Recursive clauses have the form

f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})

for R-semantics\textsf{R-semantics}0, where R-semantics\textsf{R-semantics}1 is a pattern of type R-semantics\textsf{R-semantics}2, R-semantics\textsf{R-semantics}3 is the subproblem argument in which R-semantics\textsf{R-semantics}4 may appear, R-semantics\textsf{R-semantics}5 is the static piece with no recursive calls, and R-semantics\textsf{R-semantics}6 is itself a well-formed and thus invertible function. Because the R-semantics\textsf{R-semantics}7 are pairwise disjoint, the invocation sites R-semantics\textsf{R-semantics}8 are distinguishable.

The reversible recurrence stack is the algebraic data-type that makes these postponed calls explicit. It is given by

R-semantics\textsf{R-semantics}9

where f:ABf : A \to B0 denotes the empty stack and each f:ABf : A \to B1 records that the f:ABf : A \to B2-th recursive clause was taken, together with the remembered static argument and the remainder of the stack. Operationally, each constructor f:ABf : A \to B3 records “we saw a recursive call of the f:ABf : A \to B4-th clause, we must later apply f:ABf : A \to B5 with the second sub-pattern argument f:ABf : A \to B6, and then continue unwinding the remainder of the stack f:ABf : A \to B7” (Kristensen et al., 2023).

This construction deforests recursion into an explicit stack of postponed f:ABf : A \to B8-calls. A plausible implication is that the stack serves as a semantic replacement for an implicit call stack, but with the frame structure derived directly from the recursive equations rather than from a runtime control mechanism.

2. Tail-recursive forward and backward transformations

The transformed program consists of a forward tail-recursive function and a backward tail-recursive inverse:

f:ABf : A \to B9

The forward direction collects recursive calls into the context until a base clause is reached, while the backward direction pops the context and re-applies inverse branch functions (Kristensen et al., 2023).

For the forward pass: R-semantics\textsf{R-semantics}02 and, equivalently, for recursive clauses,

f(pk)=tkf(p_k) = t_k0

No further computation occurs after the recursive call, so the transformation is tail-recursive.

For the backward pass: R-semantics\textsf{R-semantics}03 In the f(pk)=tkf(p_k) = t_k1 case, f(pk)=tkf(p_k) = t_k2 must have arisen from some base-clause result f(pk)=tkf(p_k) = t_k3; since the original function is well-formed and injective on each branch, f(pk)=tkf(p_k) = t_k4 is uniquely invertible to the original f(pk)=tkf(p_k) = t_k5-form. In the framed case, the remembered static component f(pk)=tkf(p_k) = t_k6 selects the appropriate inverse f(pk)=tkf(p_k) = t_k7 and the computation proceeds by unwinding the stack.

The abstract characterization of the method emphasizes two points: calls are highlighted, and a tail-recursive inverse can be straightforwardly extracted (Kristensen et al., 2023). This suggests that the context is not merely a storage device but the central carrier of invertible control information.

3. Reversible list reversal as a worked example

The paper’s concrete example is the self-inverse recursive list reverse: R-semantics\textsf{R-semantics}04 Here there is one recursive clause, with f(pk)=tkf(p_k) = t_k8, f(pk)=tkf(p_k) = t_k9, kKk \in K0, and kKk \in K1 (Kristensen et al., 2023).

The corresponding context data-type is: R-semantics\textsf{R-semantics}05 The forward tail-recursive phase is R-semantics\textsf{R-semantics}06 and the backward unwinding phase is R-semantics\textsf{R-semantics}07 where kKk \in K2 is the inverse of the remembered kKk \in K3-application. Concretely, kKk \in K4, given kKk \in K5 and the remembered kKk \in K6, recovers kKk \in K7.

The reconstructed composite definition is R-semantics\textsf{R-semantics}08 and the paper states that one checks by a simple induction on list length that

kKk \in K8

(Kristensen et al., 2023).

The example is significant because it isolates the mechanism of the reversible recurrence stack in a familiar recursive function: one forward pass removes recursive nesting by accumulating frames, and one backward pass reconstructs the original input by consuming those frames in reverse order.

4. Correctness, invertibility, and semantic status

The correctness argument is given as a proof sketch by structural induction on the depth of the call stack. For list reversal, the required equalities are

kKk \in K9

(Kristensen et al., 2023). In the base step, pkp_k0 and then pkp_k1 because the base clause is itself invertible. In the induction step, one assumes the claim for a smaller context and shows that one more frame reconstructs the original recursive argument by applying pkp_k2 with the remembered static value and then continuing unwinding.

In the general case, each pkp_k3 enforces the unique choice of pkp_k4, and the well-formedness condition—expressed as orthogonality of patterns—guarantees determinism of push/pop behavior and thus global invertibility (Kristensen et al., 2023). The paper’s central methodological claim is precisely that functions introduced by program transformations that preserve invertibility need only be invertible in the context in which the transformed function calls them.

This emphasis on global invertibility rather than local reversibility distinguishes the construction from standard CPS-based tail-recursion conversion, which the paper describes as deeply problematic in reversible programming because it relies on troublesome features such as higher-order functions (Kristensen et al., 2023). A related semantic distinction appears in pkp_k5: the commonly used method of reversibilization yields partial bijective functions by halting when unique reconstruction of the starting state is impossible, whereas the pkp_k6 makes all terms total bijections on an appropriate state space (Palazzo et al., 9 Jan 2025). A common misconception is therefore to treat all “reversible” stack formalisms as partial-bijection schemes; the cited work shows that total bijective operational semantics is also attainable.

5. Cost model and producer/consumer realization

For the context-based tail-recursion transformation, the depth of the pkp_k7 stack equals the recursion depth of the original function on the given argument; in the worst case, this is the same as the original recursive depth, such as pkp_k8 for a list of length pkp_k9 (Kristensen et al., 2023). Each recursive step in the forward pass pushes one small frame of size AA0 and performs AA1 work aside from pattern matching; the backward pass performs a matching number of pop steps, each applying one inverse call AA2, again AA3 per frame. Overall time and space remain AA4 as in the original, with constant overhead for constructing and deconstructing the explicit stack and invoking the inverse functions. The paper further states that, in a real implementation, the two tail-recursive passes can be collapsed into a single loop over AA5, eliminating additional call-stack overhead and leaving only heap-allocated context frames (Kristensen et al., 2023).

A distinct but closely related implementation pattern is the split into reversible and classical interacting threads. In "Splitting recursion schemes into reversible and classical interacting threads" (Matos et al., 2021), a simple recursive function

AA6

is compiled into the parallel composition

AA7

The reversible producer thread unfolds recursion depth by iterating AA8 down to the base case, sends the depth AA9, then rewinds via tkt_k0 and emits the arguments required by the classical consumer. The consumer receives the base-case argument, computes tkt_k1, and then computes tkt_k2 in lock-step with producer unwinding. Under the assumption tkt_k3, the producer and consumer both run in tkt_k4 time, and the producer’s ancilla overhead is tkt_k5 (Matos et al., 2021).

This split realizes a reversible recurrence stack without storing an explicit chain of full activation records. A plausible implication is that the context-stack view and the producer/consumer view are complementary: the first externalizes postponed calls as algebraic frames, while the second externalizes recursion depth and unwinding arguments as synchronized communication.

6. Language-level and processor-level realizations

At the language level, "Reversible Computation with Stacks and 'Reversible Management of Failures'" extends tkt_k6 with the constructs tkt_k7 and tkt_k8 over a distinguished variable tkt_k9, the call-stack register (Palazzo et al., 9 Jan 2025). A global configuration is

BB0

with BB1, so every variable carries a current value, a value-stack, and a failure-counter. The paper states the key cancellation lemma

BB2

and from this derives that the operational semantics is a total bijection on the global configuration space. In recursive settings, attempted illegal pops do not crash the machine; instead they increment the local failure-counter, and subsequent pushes can repair the variable. The account explicitly states that there is never a hard failure, even under arbitrarily nested calls, because backward execution recovers a clean original state frame by frame.

At the processor level, ReveR provides a concrete reversible call/return stack in hardware-like form (Vlasov, 2011). Its state vector is

BB3

with BB4 holding an address into unified memory. A BB5 executes a reversible exchange BB6 followed by BB7, and a BB8 executes BB9 then exchanges f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})0. Procedure calls use the assembler mnemonic f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})1, which pushes the old f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})2 onto the stack; returns use f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})3, which pops that stored f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})4 and corrects it by a known offset so that the external update f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})5 lands exactly one instruction past the call site. During nested or recursive invocations, the stack grows downward and shrinks back in the exact reverse order, and a single call pushes one f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})6-bit word (Vlasov, 2011).

Taken together, these realizations show that a reversible recurrence stack is not confined to source-level program transformation. It can be expressed as a semantic discipline in a reversible imperative language and as an operational mechanism in a reversible processor architecture.

The phrase “reverse stack” also appears in combinatorics, but there it denotes something different. In "Passing through a stack f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})7 times with reversals" (Mansour et al., 2018), a permutation is repeatedly passed through a single stack, elements are popped only when the top matches the next output value, and any remaining entries are returned to the input in reverse order at the end of the pass. The resulting notion of rev-tier is the minimal number f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})8 such that the permutation is sorted by f(pi)=gi(qi0,qi1)f(p_i) = g_i(q_{i0}, q_{i1})9 reverse passes.

This is a stack-sorting model rather than a model of reversible recursion or invertible program execution. Its “reversal” refers to reversing residual stack contents between passes, not to inverting computation. The distinction matters because the reversible recurrence stack concerns preservation of information and extraction of an inverse computation, whereas reverse-pass stack sorting concerns permutation classes, separated pairs, finite bases, and generating functions (Mansour et al., 2018).

Within reversible computing proper, the core idea remains stable across the cited work: recursion is made compatible with inversion by explicitly preserving the information that an ordinary call stack would otherwise hide or erase. In the algebraic formulation, that information is stored as R-semantics\textsf{R-semantics}00 constructors; in interacting-thread realizations, it is transmitted as depth and unwind arguments; in R-semantics\textsf{R-semantics}01 and ReveR, it is maintained by bijective push/pop and call/return rules.

Topic to Video (Beta)

No one has generated a video about this topic yet.

Whiteboard

No one has generated a whiteboard explanation for this topic yet.

Follow Topic

Get notified by email when new papers are published related to Reversible Recurrence Stack.