Commit 301da89a authored by Bruno Corrêa Zimmermann's avatar Bruno Corrêa Zimmermann
Browse files

basic trampolin

parents
*~
/target
**/*.rs.bk
Cargo.lock
[package]
name = "tramp"
version = "0.1.0"
authors = ["Bruno Corrêa Zimmermann <brunoczim@gmail.com>"]
[dependencies]
use std::fmt;
#[derive(Debug)]
pub enum Rec<T> {
Rtrn(T),
Call(Thunk<Rec<T>>),
}
pub fn tail_call<T>(fun: impl FnOnce() -> Rec<T> + 'static) -> Rec<T> {
Rec::Call(Thunk::new(fun))
}
pub fn ret<T>(val: T) -> Rec<T> {
Rec::Rtrn(val)
}
pub fn rec<T>(start: impl FnOnce() -> Rec<T> + 'static) -> T {
let mut res = start();
loop {
match res {
Rec::Rtrn(x) => break x,
Rec::Call(thunk) => res = thunk.compute(),
}
}
}
pub struct Thunk<T> {
fun: Box<FnThunk<Out = T>>,
}
trait FnThunk {
type Out;
fn call_boxed(self: Box<Self>) -> Self::Out;
}
impl<T, F> FnThunk for F
where
F: FnOnce() -> T,
{
type Out = T;
fn call_boxed(self: Box<Self>) -> T {
(*self)()
}
}
impl<T> Thunk<T> {
pub fn new(fun: impl FnOnce() -> T + 'static) -> Self {
Self {
fun: Box::new(fun),
}
}
pub fn compute(self) -> T {
self.fun.call_boxed()
}
}
impl<T> fmt::Debug for Thunk<T> {
fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
write!(fmtr, "thunk {} ptr: {:?} {}", '{', &*self.fun as *const _, '}')
}
}
extern crate tramp;
use tramp::*;
fn factorial(n: u128) -> u128 {
fn fac_acc(n: u128, acc: u128) -> Rec<u128> {
if n > 1 {
tail_call(move || fac_acc(n - 1, acc * n))
} else {
ret(acc)
}
}
rec(move || fac_acc(n, 1))
}
#[test]
fn test_fac() {
assert_eq!(factorial(5), 120);
}
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment