Open ebfull opened 8 years ago
By the way, the above macro might be useful for users to reason about Rec
and Var
. You can think of Rec
like loop { }
and Var
like continue
.
proto!(Whatever = loop {
Recv usize,
Choose {
{
Recv usize,
Send usize,
continue
},
{
Send usize,
End
},
{
loop {
Recv usize,
Choose {
continue,
continue 1
}
}
}
}
}
);
Now that GATs are stabilized, it seems one could easily leverage them to define type-level fixpoints:
pub trait Fix {
type Def<T>: HasDual where T: HasDual;
}
impl<T> Chan<T>
where
T: Fix,
{
pub fn fix(self) -> Chan<<T as Fix>::Def<T>> {
unsafe { transmute(self) }
}
}
impl<T> HasDual for T where T: Fix {
type Dual = T;
}
// example use
struct MyLoop();
impl Fix for MyLoop {
type Def<T> = Recv<usize, Send<usize, T>> where T: HasDual;
}
fn srv(mut c: Chan<MyLoop>) {
loop {
let cc = c.fix();
let (cc, value) = cc.recv();
c = cc.send(value);
}
}
Would there be any downside with this approach?
Associated types are powerful enough to avoid needing an environment stack or recursive session types.
Cool, but it requires ugly struct definitions and impls at every depth. I think this downside is mentioned throughout session type literature. It's not practical, they said. Just use recursive session types, they said.
But wait, there's macros!
Unfortunately the macro necessary to expand such a construct is ridiculously complex (and this is after omitting recursion, choose/offer, etc.):