Inspiration

I originally became interested in building a domain-specific language that could make quantum programming easier. Quantum programs frequently need uncomputation: running part of a computation backward to clean up temporary state without destroying the result. While searching for a natural way to express this, I discovered Janus, a reversible programming language where call runs a procedure forward and uncall runs the same procedure backward.

What surprised me was that this idea felt relevant far beyond quantum computing.

Modern software constantly pairs operations with their opposites: acquiring and releasing resources, deploying and rolling back services, or unwinding the completed steps of a failed workflow. Existing language features handle important scope-local cases, but developers still often have to write and maintain inverse control flow explicitly.

This becomes especially relevant in the age of AI-assisted development. AI can generate and modify forward behavior quickly, but a human must still verify that cleanup or rollback logic follows the updated control flow. When the two paths are maintained separately, they can drift apart.

Janus offers a different model: reverse computation is derived from the semantics of the same program. This does not make every real-world effect perfectly reversible, but it can reduce the inverse control flow that developers must write and verify by hand.

I built UNCALL to explore this idea, starting with reversible algorithms, extending it to effectful workflows, and finally returning to the quantum-programming motivation that led me to Janus.

What it does

UNCALL is a browser-based implementation of a practical, Janus86-inspired reversible programming core.

A single procedure can be executed in both directions. For example, the same encode procedure encrypts text when called and decrypts it when uncalled. There is no separately written decoder.

The interactive demos cover five applications of reversible computation:

  • Encryption and decryption
  • Reversible sorting that preserves only the information needed to restore the input
  • Tree traversal that records a path and uses it to return to the original leaf
  • A three-qubit Quantum Fourier Transform and its inverse
  • A four-bit reversible adder that becomes subtraction when run backward

Users can edit the displayed Janus code and inputs, then execute both directions entirely in the browser.

UNCALL also includes a separate runtime for effectful workflows. It connects operations to paired forward and backward handlers, records receipts for completed actions, cleans up partial failures in reverse order, detects workflow drift, and can resume cleanup from a serialized execution record.

How I built it

I built UNCALL in TypeScript and deployed it on Cloudflare Workers using Hono. The browser applications are bundled with esbuild and run without an account or server-side session.

The Pure Janus implementation has separate stages for tokenization, parsing, static checking, name resolution, and execution. Its direction-aware evaluator reverses both statement order and operation semantics when a procedure is uncalled.

The language supports integer variables, fixed-length arrays, reversible updates and swaps, conditionals with exit assertions, reversible loops, procedure calls, forward references, bounded recursion, and static alias checks.

I kept deterministic Pure Janus computation separate from external effects. The host runtime represents each capability as a primitive with paired forward and backward handlers. Forward operations produce receipts identifying the concrete resources they affected, and backward execution consumes those receipts.

For the quantum demos, I reused this primitive pipeline to emit reversible gates. The QFT demo uses a complex state-vector simulator, while the adder uses computational-basis simulation with X, CNOT, and Toffoli gates.

I used Codex with GPT-5.6 throughout design, implementation, debugging, testing, documentation, and review. I chose the product direction, implementation boundaries, demos, and the guarantees the project could honestly make. UNCALL itself is deterministic and does not call a language model at runtime.

Challenges I ran into

The main challenge was not implementing the interpreter, but finding a demonstration that clearly communicated why reversible programming is different from ordinary cleanup.

My initial idea was an infrastructure workflow that created several resources and removed them in reverse order. However, this looked very similar to existing mechanisms such as try/finally, RAII, using, or a disposal stack. Those mechanisms already handle scope-local cleanup well, so reverse-order deletion alone did not justify a new language model.

I had to reconsider what the project should demonstrate. UNCALL does not merely register cleanup callbacks; it derives inverse computation from the semantics and control flow of the same program. I therefore shifted the main experience toward editable Pure Janus examples such as reversible sorting, encryption, and tree traversal, where users can see program state being transformed and reconstructed. I placed the quantum demos on a separate page, where inverse gates make the original motivation especially concrete.

This also forced me to be precise about the project’s claims. UNCALL can derive inverse control flow, but it cannot make every external effect perfectly reversible. Finding a demo that made the core idea visible without overstating that guarantee was the most difficult product decision in the project.

Accomplishments that I'm proud of

I am most proud that UNCALL is a real editable language implementation, not a fixed animation. The code displayed in the browser is the code that gets tokenized, parsed, checked, linked, and executed.

Other accomplishments include:

  • Implementing a Janus86-inspired reversible language core from scratch
  • Producing both forward and backward behavior from one procedure definition
  • Supporting reversible updates, swaps, conditionals, loops, arrays, and recursion
  • Creating five interactive demos that run entirely in the browser
  • Passing 81 automated tests, including exhaustive verification of all 256 four-bit adder inputs

I am also proud that UNCALL defines its limits honestly: the runtime derives inverse control flow, while primitive authors remain responsible for defining what reversal means for each external effect.

What I learned

Building UNCALL showed me how dramatically AI is changing what an individual developer can create. Implementing a parser, static checker, resolver, and reversible runtime for a relatively obscure language would traditionally have been a difficult and time-consuming project. With Codex, much of that work became surprisingly manageable.

As implementation becomes more automated, I believe the essential questions increasingly become what I intend to build, what I want to express, and how I verify that the result reflects that intent. This idea is not new, but building UNCALL convinced me that the shift is accelerating.

I also learned that reversible programming is not free. Janus preserves reversibility by preventing information from being lost. For example, a conventional sorting algorithm discards the outcomes of its comparisons, while a reversible sort must retain enough of that trace to reconstruct the original order.

Like formal methods, reversible programming provides stronger guarantees in exchange for constraints and additional obligations. AI can help implement and verify programs within those rules, but it cannot eliminate the underlying information-theoretic trade-offs. Reversible programming may therefore be most valuable in domains where inverse execution is important enough to justify those constraints.

What's next for UNCALL

My first goal is to improve the integration between the Janus runtime and TypeScript host applications. I want developers to be able to embed reversible procedures, define typed host primitives, and connect forward and backward behavior as a flexible part of an existing TypeScript application.

I also want to discover practical use cases where derived inverse control flow provides enough value to justify the constraints of reversible programming.

Finally, I want to return to the project’s original motivation and explore UNCALL as a quantum-programming DSL—particularly for generating reversible circuits, managing temporary state, and making uncomputation easier to express and verify.

Built With

Share this project:

Updates