Spiral: a functional language where staging and type features keep arriving
Functional language with intensional polymorphism and first-class staging.
At a glance
- What is it?
- The Spiral Language is a research language built around first-class staging and intensional polymorphism, with a C backend, a Python backend and a Python plus Cuda backend that compiles the whole language down to device code. It is documented in depth, it has no releases, and its own documentation keeps a section listing known bugs.
- Who is it for?
- Adopt Spiral only if you are writing experimental staged programs, especially device side kernels, and are prepared to read a language design document that is still changing, since existentials, GADTs and higher ranked types all arrived within four months in 2024. Do not adopt it as production infrastructure: there are no GitHub releases, no packaged install path, and the documentation itself carries a Known Bugs section.
- Can I use it commercially?
- Yes, with conditions. MPL-2.0 is a weak copyleft licence: you can use it inside commercial and closed-source software, but if you distribute changes to its own files, you must publish those changes under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 115 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Staging is the point, not a feature added later
Spiral is described in one line as a functional language with intensional polymorphism and first-class staging. That combination is what separates it from a general purpose functional language, and it explains why the project has a compiler with join points, macros and layout types rather than a library of combinators.
Staging means the language can treat code as a value. A program can build a program, and the compiler can check the generated form against the same type system that checked the generator. Intensional polymorphism is the neighbouring capability, letting types depend on type-level values rather than only on type constructors. Together they let a programmer write, in one language, both the transformation applied to data and the transformation applied to code.
The audience follows from that. The documentation is written for people who want to read about type systems and compilation strategy, and the news entries in the README describe the work in terms of what the language can now express. This is a research project, and the interesting question for an engineer is whether its ideas are worth studying, not whether it can carry a production service.
The manual is split into a top-down segment and a bottom-up segment
The table of contents shows how the documentation is organised, and the split is unusual enough to be worth describing. The Top-Down Segment covers Compilation, Basics, Join points, Functions, what triggers dyning, Macros, Layout types, Nominals, Symbols with Records and Unions, Type Literals including the v operator in macros, Prototypes, Existentials, GADTs and Higher Ranked Types. The Bottom-Up Segment covers Functions, Branching, Loop Unrolling, Compiler Crashing, Print Static, Type Inference In Bottom-Up Style, and Real Nominals And Inverse Arrays.
Several headings are warnings rather than topics. A section on the heap allocation versus code size tradeoff tells you the authors consider allocation a first-class cost. A section titled Compiler Crashing sits inside the branching discussion. A Known Bugs section closes the document. For a language at this stage that is unusual candour, and it tells a reader exactly where the sharp edges are instead of leaving them to be discovered.
The two segments also suggest two audiences, or two ways of reading. The top-down text is for understanding what the language means, and the bottom-up text is for understanding what the compiler does with it.
Existentials, GADTs and higher ranked types all landed in 2024
The news entries in the README read as a development log, and three of them describe type system changes inside a single year. On 3/30/2024 existentials were added in v2.8.0, which introduced a new `exists` keyword and was therefore a breaking change; the author suggests renaming variables called `exists` to `exists'`. On 7/5/2024 GADTs were added, with the reason given plainly: they are needed for the ML library. On 7/28/2024 higher ranked types were added, and the stated motivation is more relaxed, since the author says they were not really needed but that it is better not to restrict the language design.
That sequence is informative. A feature requested by a downstream project lands first, and a feature adopted as a matter of principle lands later, with the reasoning written down in public. It also tells you where the pressure comes from. The ML library is the driver, and it in turn is aimed at training reinforcement learning agents on poker games, in work described as a single fully fused kernel.
The stated plan at the time of those entries was to continue the ML library and use it to train the agents, with the games already implemented and architected for use in ML pipelines. The README does not say that this work completed.
The Cuda backend reaches the whole language through function pointers and closures
The 6/17/2024 entry is the longest and it marks a change in ambition for the GPU target. The Python plus Cuda backend was extended with C++ style reference counting so that it supports heap allocated closures, recursive unions and layout types, and the entry says the earlier version could be considered a prototype while the new one supports the full range of the language's features. The stated purpose is single threaded GPU programming.
Two function types were added to the language specifically for this backend, and the conversion is explicit:
fptr
closure
to_fptr
to_closureBecause these types rely on native C++ features based on shared pointers for reference counting, the README states they are completely interoperable with existing C++ libraries. It adds a weaker but useful path: regular Spiral functions can be interop'd with C++ as long as they are not returned or passed through join points and their types are not printed anywhere other than their origin by the code generator, in which case they compile to stack allocated C++ functors that can capture free variables and be passed into macro expressions. The core library also gained two dynamic array classes usable directly in device side Cuda kernels, with serialization code for them.
The entry is honest about a cost. The author could not get the compilation times for the NL Holdem example down significantly using the new dynamic arrays, and says it will be up to the Cuda team to bring those down.
Backends arrived in sequence, and the project is one person's work
The news section doubles as a history of the implementation. An entry dated 8/21/2021 says only that the docs were updated, and the table of contents still contains a status section labelled with the date 8/17/2021, which is the kind of heading that tells you status prose in this project goes stale unless someone edits it. A C backend is announced on 7/13/2022, a Python backend on 12/21/2022, and a UPMEM demo and backend on 1/7/2023. A Spiral playlist on YouTube was posted on 8/27/2023.
The voice throughout is first person singular, and the repository layout matches a single researcher's workspace rather than a community project:
The Spiral Language 2/
Spiral Compilation Tests/
VS Code Plugin/There is a Visual Studio solution file at the root, a directory of compilation tests, and a separate directory holding the second version of the language. A VS Code Plugin directory suggests the editor tooling is part of the same tree. The repository page records the primary language as Python, which is an artefact of how the project is hosted and built rather than a description of the language being implemented.
The consequence for a reader is that bus factor is one. The documentation is thorough, but the news entries are written by the person doing the work, and the release history shows a single author making architectural decisions and announcing them in the README.
No releases, an MPL licence, and a changelog that is not a release note
The repository publishes no GitHub releases, which is unusual for a project with this much documentation and several working backends. The version number that appears in the README is a language version, v2.8.0, mentioned in the existentials entry, and the tree includes a CHANGELOG file alongside the LICENSE file. A changelog without releases is a development record rather than a distribution channel, and there is no packaging metadata in the tree, so obtaining a usable compiler means building from the source directories.
The licence is MPL-2.0. The practical difference from a permissive licence is file-level copyleft: if you modify MPL-licensed files, your modified versions of those files must be made available under the same terms when you distribute them. Linking or incorporating the language in a larger system is a different question from that one, and the LICENSE file is the place to read the terms rather than take them from this paragraph.
The repository is not archived, and the last push was on 2026-06-30, so the work continues. What it does not tell you is how the last push relates to the version in the news entries, since no release was cut to match it. Anyone adopting this has to build from source and track the repository history rather than a versioned artefact.
Writing the generator in a host language instead of in Spiral
The realistic alternative to Spiral is not another staged language but a familiar host language. The Python backend already exists, so a team can write a generator in Python, emit C or Cuda source, and let the target compiler check the result. The difference in approach is where the type checking happens.
In that arrangement, the generator is checked by Python's type system, which says nothing about the shape of the code it emits, and the emitted code is checked by the C or Cuda compiler, which is too late to give feedback about the generator's intent. Spiral instead makes the generated program a value in the same language, so join points, layout types and the rest of its type system apply to the generated form.
The trade-off runs the other way as well. Spiral's own compiler crashing, its known bugs section, its type inference differences between the top-down and bottom-up styles, and the compilation time problem the author reports for a large example are all costs you take on in exchange for that guarantee. The decision therefore depends on whether the staged program is the hard part of your work. If it is, the language helps. If the staging is incidental and the real problem is the domain, a host language generator with a target compiler is the cheaper path.
Editorial conclusion
Adopt Spiral only if you are writing experimental staged programs, especially device side kernels, and are prepared to read a language design document that is still changing, since existentials, GADTs and higher ranked types all arrived within four months in 2024. Do not adopt it as production infrastructure: there are no GitHub releases, no packaged install path, and the documentation itself carries a Known Bugs section. Verify first that the compiler builds on your machine from the Visual Studio solution and the second language directory, that the Cuda backend supports the features your program needs, and that MPL-2.0 terms in the LICENSE file suit how you intend to distribute the code.
Frequently asked questions
What is the Spiral programming language?
Spiral is described as a functional language with intensional polymorphism and first-class staging, documented in a top-down segment about language features and a bottom-up segment about compiler behaviour. It has C, Python and Python plus Cuda backends.
How do I get the Spiral compiler?
The repository publishes no releases and no packaged install, so the compiler is built from source, using the Visual Studio solution file and the second language directory in the tree. The documentation has a Getting Spiral section for the details.
What is new in recent versions of Spiral?
Existentials were added in v2.8.0 on 3/30/2024 with a new `exists` keyword, GADTs were added on 7/5/2024 for the ML library, and higher ranked types were added on 7/28/2024. The repository was last pushed on 2026-06-30.
Can Spiral code call into C++ libraries from Cuda kernels?
Yes, through the `fptr` and `closure` types and the `to_fptr` and `to_closure` conversions, which use native C++ shared pointer reference counting and are stated to be completely interoperable with existing C++ libraries. Regular Spiral functions can also be interop'd with C++ within the limits described in the documentation.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/mrakgr-the-spiral-language)Was this useful?