Skip to content

Instantly share code, notes, and snippets.

@ClarkeRemy
Created February 20, 2024 05:55
Show Gist options
  • Save ClarkeRemy/b613c776512d3ddb1016ecccd64afa13 to your computer and use it in GitHub Desktop.
Save ClarkeRemy/b613c776512d3ddb1016ecccd64afa13 to your computer and use it in GitHub Desktop.
Rust CPS tree traversal
fn main() {
let sub = |x,y| Diff::Sub((Box::new(x), Box::new(y)));
let lit = |x| Diff::Lit(x);
let tree = sub(sub(lit(5.0), lit(2.0)), lit(3.0));
let tree2 = tree.clone();
println!("tree : {:?}\ntree2: {:?}",
expr(tree)(id()),
expr2(tree2)(id())
);
}
#[derive(Debug, Clone)]
enum Diff {
Sub((Box<Diff>, Box<Diff>)),
Lit(f64),
}
type DynFnOnce<A,O> = Box<dyn FnOnce(A)->O>;
fn id<T>()->DynFnOnce<T,T> {Box::new(|t|t)}
// explicit CPS
fn expr(d : Diff) -> DynFnOnce< DynFnOnce<f64,f64>, f64> {
match d {
Diff::Lit(x) => Box::new(move|k| k(x)),
Diff::Sub((l,r)) =>
Box::new(move|k| expr(*l)(
Box::new(move|m| expr(*r)(
Box::new(move|n| k(m-n))
)))),
}
}
// do notation?
fn expr2(d : Diff) -> DynFnOnce< DynFnOnce<f64,f64>, f64> {
match d {
Diff::Lit(x) => Box::new(move|k| k(x)),
Diff::Sub((l,r)) =>
seq!{
|k| expr(*l);
|m| expr(*r);
|n| k(m-n);
},
}
}
#[macro_export]
macro_rules! __seq {
(|$NAME:ident| $STEP:expr;) => { Box::new(move|$NAME| $STEP) };
( |$NAME0:ident| $STEP0:expr; $(|$NAME1:ident| $STEP1:expr;)+
) => {
Box::new(move|$NAME0| $STEP0(__seq!($(|$NAME1| $STEP1;)+)))
};
}
use crate::__seq as seq;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment