~ November 18, 2025
The Rust typing system is a functional language! It was only after stumbling across this by myself for the first time that I realized it’s actually a wide-spread topic of discussion. I still find it very cool and this serves as personal notes for how it works.
struct Cons {
val: i32,
next: Option<Box<Cons>>
} can be written as the following. Note that we do need a PhantomData placeholder to keep the compiler happy.
struct Cons<Val, Next>(PhantomData<(Val, Next)>); Use Peano numbers!
struct Zero;
struct Succ<N>(PhantomData<N>); Then we can write
type One = Succ<Zero>;
type Two = Succ<One>;
// etc. And equivalently in Rust for future reference is:
enum PeanoNumber {
Zero,
Succ(Box<PeanoNumber>)
} enum PeanoNumber {
Zero,
Succ(Box<PeanoNumber>)
}
fn sub_one(x: PeanoNumber) -> PeanoNumber {
match x {
PeanoNumber::Zero => PeanoNumber::Zero,
PeanoNumber::Succ(y) =>
}
} can be written as
struct Zero;
struct Succ<N>(PhantomData<N>);
trait AddOne {
type Output;
}
impl AddOne for N {
type Output = Succ<N>;
} Putting it all together we get:
#![allow(dead_code)]
use std::marker::PhantomData;
// we can technically use a trait Nat to "group" Zero and Succ
struct Zero;
struct Succ<N>(PhantomData<N>);
trait Add {
type Output;
}
impl<N> Add for (N, Zero) {
type Output = N;
}
impl<N, M> Add for (N, Succ<M>)
where
(Succ<N>, M): Add,
{
type Output = <(Succ<N>, M) as Add>::Output;
}
type One = Succ<Zero>;
trait Fibonacci {
type Output;
}
impl Fibonacci for Zero {
type Output = Zero;
}
impl Fibonacci for One {
type Output = One;
}
impl<N> Fibonacci for Succ<Succ<N>>
where
N: Fibonacci,
Succ<N>: Fibonacci,
(<Succ<N> as Fibonacci>::Output, <N as Fibonacci>::Output): Add,
{
type Output = <
(
<Succ<N> as Fibonacci>::Output,
<N as Fibonacci>::Output
) as Add
>::Output;
}
trait Print {
const OUTPUT: u32;
}
impl Print for Zero {
const OUTPUT: u32 = 0;
}
impl<N: Print> Print for Succ<N> {
const OUTPUT: u32 = <N as Print>::OUTPUT + 1;
}
fn main() {
type Two = <(One, One) as Add>::Output;
type Four = <(Two, Two) as Add>::Output;
type Eight = <(Four, Four) as Add>::Output;
type Ans = <Eight as Fibonacci>::Output;
println!("{}", <Ans as Print>::OUTPUT); // 21
}