Skip to content

Instantly share code, notes, and snippets.

@hirrolot
Last active October 1, 2024 17:12
Show Gist options
  • Save hirrolot/5b3babf7972bdcc7d236cf891a925f6a to your computer and use it in GitHub Desktop.
Save hirrolot/5b3babf7972bdcc7d236cf891a925f6a to your computer and use it in GitHub Desktop.
Tagless-final encoding of a simple arithmetic language in Rust
trait Interp {
type Repr<T>;
fn lit(i: i32) -> Self::Repr<i32>;
fn add(a: Self::Repr<i32>, b: Self::Repr<i32>) -> Self::Repr<i32>;
}
struct Eval;
impl Interp for Eval {
type Repr<T> = i32;
fn lit(i: i32) -> Self::Repr<i32> {
i
}
fn add(a: Self::Repr<i32>, b: Self::Repr<i32>) -> Self::Repr<i32> {
a + b
}
}
struct Print;
impl Interp for Print {
type Repr<T> = String;
fn lit(i: i32) -> Self::Repr<i32> {
format!("{i}")
}
fn add(a: Self::Repr<i32>, b: Self::Repr<i32>) -> Self::Repr<i32> {
format!("({a}) + ({b})")
}
}
struct Neg<I>(std::marker::PhantomData<I>);
impl<I: Interp> Interp for Neg<I> {
type Repr<T> = I::Repr<T>;
fn lit(i: i32) -> Self::Repr<i32> {
I::lit(-i)
}
fn add(a: Self::Repr<i32>, b: Self::Repr<i32>) -> Self::Repr<i32> {
I::add(a, b)
}
}
fn expr<I: Interp>() -> I::Repr<i32> {
I::add(I::lit(42), I::add(I::lit(1), I::lit(2)))
}
fn main() {
dbg!(expr::<Eval>()); // 45
dbg!(expr::<Print>()); // "(42) + ((1) + (2))"
dbg!(expr::<Neg<Eval>>()); // -45
dbg!(expr::<Neg<Print>>()); // "(-42) + ((-1) + (-2))"
}
@hirrolot
Copy link
Author

hirrolot commented Dec 22, 2022

Borrowed from "Tagless-final primer" of Oleg Kiselyov.
Playground >>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment