DEV Community

Yufan Lou
Yufan Lou

Posted on

3

(Maybe) Tagless Final in Rust

Why the biggest take away from Tagless Final has been the type class abstraction, I am kinda confused now. Anyway.

I thought I couldn't enforce types in the operators. That is wrong. I just cannot enforce types in the operators as confined in a trait. That's where the Higher-Kinded Type is useful.

#![allow(dead_code)]
#![allow(non_snake_case)]

/*
let varZ env = fst env
let varS vp env = vp (snd env)
let b (bv:bool) env = bv
let lam e env = fun x -> e (x,env)
let app e1 e2 env = (e1 env) (e2 env)
*/

type Func<T, O> = Box<dyn FnOnce(T) -> O>;

fn varZ<A, B>() -> Func<(A, B), A> {
    Box::new(|env| env.0)
}

fn varS<A, T1: 'static, T2: 'static>(vp: Func<T1, T2>) -> Func<(A, T1), T2> {
    Box::new(move |env| vp(env.1))
}

fn b<P>(bv: bool) -> Func<P, bool> {
    Box::new(move |_env| bv)
}

fn lam<A: 'static, B: 'static, T: 'static>(e: Func<(A, B), T>) -> Func<B, Func<A, T>> {
    Box::new(|env| Box::new(|x| e((x, env))))
}

fn app<T1: 'static + Copy, T2: 'static, T3: 'static>(
    e1: Func<T1, Func<T2, T3>>,
    e2: Func<T1, T2>,
) -> Func<T1, T3> {
    Box::new(|env| e1(env)(e2(env)))
}

fn main() {
    let testf1 = app(lam(varZ()), b(true));
    println!("{}", testf1(()));
    let testf3 = app(lam(varS(varZ())), b(true));
    println!("{}", testf3((1, (2))));
}

Sentry image

See why 4M developers consider Sentry, “not bad.”

Fixing code doesn’t have to be the worst part of your day. Learn how Sentry can help.

Learn more

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay