Admiran is a pure, lazy, functional language and self-hosting compiler based upon Miranda
Assembly
119
555 commits
updated Sep 20, 2026
Admiran is a pure, lazy, functional language and self-hosting compiler, based upon the original Miranda language designed by David Turner, with additional features from Haskell and other functional languages.
Here's a small example of an Admiran program, to generate and print a list of the first 100 primes:
|| primes.am -- generate primes the lazy recursive way
|| From David Turner's original "sieve" example
|| io functions which communicate with the outside world (like putStrLn) are defined in the <io> module
%import <io>
primes :: [int] || an optional type spec for primes, which is a list of ints
primes = sieve [2 ..] || defines primes as the result of calling the sieve function on an
|| infinite list of sequential integers, starting from 2
where
|| the sieve function deconstructs the list into its head (p) and tail (xs)
|| and returns p (the next prime) followed by a recursive call to sieve
|| on a new list made from a list comprehension, which filters the remaining list
|| for only the values that aren't divisible by p
sieve (p : xs) = p : sieve [x | x <- xs; x $mod p ~= 0]
|| main takes the first 100 values from the infinite list of primes, converts that list to
|| a string, and prints it, chaining together the functions using the `|>` reverse-apply
|| function defined in the <stdlib> module (implicitly imported).
main :: io ()
main = primes |> take 100 |> showlist showint |> putStrLn
Some other small example programs are in the examples directory. They can be built with the Makefile in that directory, or individually
by typing amc module name e.g. amc fib. Note that amc is a whole-program compiler, so you only need to specify the top-level module
that contains the "main" function; all other required modules will be built as required.
Hundreds of other examples can be found in my 10 years of Advent of Code solutions, and the amc compiler itself is an example of a large, multi-module Admiran program.
Admiran is an "extended subset" of Miranda, an ML-like language, and has all its basic features:
In addition, Admiran has features found in other functional languages, like Haskell and F#:
The Admiran compiler is written in Admiran (self-hosting). The goal is to implement the entire compiler pipeline, from source tokenization through to low-level asm code generation, while keeping the compiler small enough (currently ~7000 SLOC in 26 modules) to be easily understandable by someone studying it.
Whole-program compilation
Parser written using parser-combinators
Desugaring to simplified core AST
Multiple analysis passes to analyze definitions for free variables, usage, complexity, and escape status for let-bound definitions
Hindley-Milner type inference and checking
Multi-pass AST optimizer, including:
AST serialization / deserialization for modules
Spineless Tagless G-Machine (STG) IR
code produced is 20x to 50x the performance of the original Miranda compiler/combinator interpreter
The Admiran library implements many useful functional polymorphic data structures, useful in both the compiler as well as user programs:
Admiran currently only runs on x86-64 based MacOS or Linux systems (or under Rosetta 2 on Apple silicon). The only external dependency is a C compiler for assembling the generated asm files and linking them with the C runtime library. This is automatically done when compiling an Admiran source file.
The Admiran compiler (amc) is written in Admiran, and requires bootstrapping from a pre-built bootstrap compiler. This is mostly automated in the Makefile, but needs a manual configuration step first:
Edit the config.am file in the compiler directory to modify the values for:
hostOS = Linux || set to Linux or MacOS
admiranLibPath = "../lib" || set to absolute path name for the lib directory, e.g.
|| "/home/tim/Programming/Admiran/lib"
then go back to the top-level directory and type "make".
The script will bootstrap the compiler in 4 stages:
When complete, it should report === amc compiler built successfully ===
and install as amc in the supplied bin directory.
It is suggested that you add the bin directory to your PATH variable in your shell, to allow the amc compiler to be run from anywhere.
After the amc compiler builds a module (before whole-program merging), it creates a ".x2" file for the module. This is a serialized version of the internal optimized Abstract Syntax Tree (AST) of the module, which can be loaded by the compiler instead of recompiling from source, again. The compiler checks the corresponding modification times of the .am and .x2 files to see if the .x2 file is up-to-date, and will re-build from the .am file if it is newer. The .x2 files can be removed to force a rebuild from the source file.
The program tools/dumpX2.am can be used to pretty-print the contents of .x2 files and show the final result of
the inlined and optimized modules.
bin/ executables are put hereboot/ contains the asm source for the two pre-built bootstrap compilers (one for Linux, one for MacOS)doc/ project documentation (language documentation complete, others in-progress)compiler/ contains the Admiran source files for the amc compilerlib/ contains the sources for the various libraries, and the runtime.c fileexamples/ contains some example programs to show Admiran syntax and to try the compiler outtools/ contains some tools built with Admiran for use on Admiran filesTo learn more about how functional languages are implemented. To have a fun project to work on that can provide a nearly endless list of to-dos. To have a fun language to write Advent Of Code solutions in. Maybe it can be useful for someone else interested in these things.
Lovingly hand-crafted with no AI.
Assembly
99.7%
Admiran is a pure, lazy, functional language and self-hosting compiler based upon Miranda
Assembly
119
555 commits
updated Sep 20, 2026
Admiran is a pure, lazy, functional language and self-hosting compiler, based upon the original Miranda language designed by David Turner, with additional features from Haskell and other functional languages.
Here's a small example of an Admiran program, to generate and print a list of the first 100 primes:
|| primes.am -- generate primes the lazy recursive way
|| From David Turner's original "sieve" example
|| io functions which communicate with the outside world (like putStrLn) are defined in the <io> module
%import <io>
primes :: [int] || an optional type spec for primes, which is a list of ints
primes = sieve [2 ..] || defines primes as the result of calling the sieve function on an
|| infinite list of sequential integers, starting from 2
where
|| the sieve function deconstructs the list into its head (p) and tail (xs)
|| and returns p (the next prime) followed by a recursive call to sieve
|| on a new list made from a list comprehension, which filters the remaining list
|| for only the values that aren't divisible by p
sieve (p : xs) = p : sieve [x | x <- xs; x $mod p ~= 0]
|| main takes the first 100 values from the infinite list of primes, converts that list to
|| a string, and prints it, chaining together the functions using the `|>` reverse-apply
|| function defined in the <stdlib> module (implicitly imported).
main :: io ()
main = primes |> take 100 |> showlist showint |> putStrLn
Some other small example programs are in the examples directory. They can be built with the Makefile in that directory, or individually
by typing amc module name e.g. amc fib. Note that amc is a whole-program compiler, so you only need to specify the top-level module
that contains the "main" function; all other required modules will be built as required.
Hundreds of other examples can be found in my 10 years of Advent of Code solutions, and the amc compiler itself is an example of a large, multi-module Admiran program.
Admiran is an "extended subset" of Miranda, an ML-like language, and has all its basic features:
In addition, Admiran has features found in other functional languages, like Haskell and F#:
The Admiran compiler is written in Admiran (self-hosting). The goal is to implement the entire compiler pipeline, from source tokenization through to low-level asm code generation, while keeping the compiler small enough (currently ~7000 SLOC in 26 modules) to be easily understandable by someone studying it.
Whole-program compilation
Parser written using parser-combinators
Desugaring to simplified core AST
Multiple analysis passes to analyze definitions for free variables, usage, complexity, and escape status for let-bound definitions
Hindley-Milner type inference and checking
Multi-pass AST optimizer, including:
AST serialization / deserialization for modules
Spineless Tagless G-Machine (STG) IR
code produced is 20x to 50x the performance of the original Miranda compiler/combinator interpreter
The Admiran library implements many useful functional polymorphic data structures, useful in both the compiler as well as user programs:
Admiran currently only runs on x86-64 based MacOS or Linux systems (or under Rosetta 2 on Apple silicon). The only external dependency is a C compiler for assembling the generated asm files and linking them with the C runtime library. This is automatically done when compiling an Admiran source file.
The Admiran compiler (amc) is written in Admiran, and requires bootstrapping from a pre-built bootstrap compiler. This is mostly automated in the Makefile, but needs a manual configuration step first:
Edit the config.am file in the compiler directory to modify the values for:
hostOS = Linux || set to Linux or MacOS
admiranLibPath = "../lib" || set to absolute path name for the lib directory, e.g.
|| "/home/tim/Programming/Admiran/lib"
then go back to the top-level directory and type "make".
The script will bootstrap the compiler in 4 stages:
When complete, it should report === amc compiler built successfully ===
and install as amc in the supplied bin directory.
It is suggested that you add the bin directory to your PATH variable in your shell, to allow the amc compiler to be run from anywhere.
After the amc compiler builds a module (before whole-program merging), it creates a ".x2" file for the module. This is a serialized version of the internal optimized Abstract Syntax Tree (AST) of the module, which can be loaded by the compiler instead of recompiling from source, again. The compiler checks the corresponding modification times of the .am and .x2 files to see if the .x2 file is up-to-date, and will re-build from the .am file if it is newer. The .x2 files can be removed to force a rebuild from the source file.
The program tools/dumpX2.am can be used to pretty-print the contents of .x2 files and show the final result of
the inlined and optimized modules.
bin/ executables are put hereboot/ contains the asm source for the two pre-built bootstrap compilers (one for Linux, one for MacOS)doc/ project documentation (language documentation complete, others in-progress)compiler/ contains the Admiran source files for the amc compilerlib/ contains the sources for the various libraries, and the runtime.c fileexamples/ contains some example programs to show Admiran syntax and to try the compiler outtools/ contains some tools built with Admiran for use on Admiran filesTo learn more about how functional languages are implemented. To have a fun project to work on that can provide a nearly endless list of to-dos. To have a fun language to write Advent Of Code solutions in. Maybe it can be useful for someone else interested in these things.
Lovingly hand-crafted with no AI.
Assembly
99.7%