
Compiling with sequent calculus
Long time lurker here. I've seen a number of posts about using IRs based on sequent calculus and decided to have a go at it myself. My prototype compiler can be found here, for those of you interested in this niche: https://github.com/August-Alm/sequent
The paper that influenced me the most was https://se.cs.uni-tuebingen.de/publications/schuster25compiling.pdf, that has been highlighted on this reddit before. It defines a low-level IR that corresponds to focused/normalized terms of a depolarised sequent calculus calculus and explains how to transpile it to traditional assembly. I copied this pretty much wholesale.
One abstraction level above it, I have a polarised sequent calculus with generalised algebraic data/codata types, higher kinded types, quantitative type theory-style usage tracking, polymorphism and automatic data kinds in the vein of Haskell's DataKinds extension, and primitive "destination" types for type-safe memory writes in destination passing style (in the style of https://arxiv.org/pdf/2503.07489).
Above that sits functional programming language users are meant to write. It supports the same type-level features, but it is not polarised. It has (generalised algebraic) data and codata types, but they have the same kind "type" ("*") -- polymorphism is higher rank and over all types, not over data or codata separately.
The compilation pipeline was pleasantly easy once. I only really faced two big conundrums:
The surface functional language is not polarised, but the core sequent calculus is. So, I shift all constructions in the surface language into the positive & producer fragment of the core. Since, e.g., function types in sequent calculus are canonically polarised as ((A:+) -> (B:-)):-, this involves quite a bit of shifting to get right. Similarly, the low-level focused/normalised IR is again unpolarised but still has a chirality division of terms into producers and consumers. The compilation of the core sequent calculus to the focused form is done in such a way that "focused chirality = core chirality + core polarity mod 2". That is, the chirality of terms of negative types flip. Again, the transformations are not really very difficult, the difficulty was realising how it needed to be done. I'm sure it has been written about in the research literature but, not being an academic, I had to reinvent the wheel for myself.
The low-level, focused IR does not support polymorphism. In fact, the focusing/normalisation of the core sequent calculus into the focused IR does not support polymorphism, or at least I couldn't figure out how to do it. The issue is that this focusing/normalisation relies crucially on eta-expansion of cuts, in a way that depends on knowing the type of the cut. A cut at a polymorphic type variable cannot be eta-expanded. To get around this, I monomorphise the core sequent terms before normalisation, based on https://dl.acm.org/doi/epdf/10.1145/3720472 That paper does not do it in the setting of a sequent calculus, but it translated very nicely into my setting and allowed me to fully monomorphise higher-rank polymorphism with very little effort.
The compiler "frontend" is very underdeveloped. No source code positions in error messages or etc, the syntax is a bit crude and types annotations could be much more inferred. But for what it is -- a prototype of compilation with sequent calculus-based IRs -- I feel it has achieved its goal. It supports high-level, feature-rich functional programming language and emits surprisingly fast Arm64 assembly, with no external dependencies apart from lexx/yacc for parsing.
