Skip to content

Instantly share code, notes, and snippets.

Created July 3, 2015 13:47
Show Gist options
  • Save anonymous/e740d3f31e5ba358ca93 to your computer and use it in GitHub Desktop.
Save anonymous/e740d3f31e5ba358ca93 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
trait Apply {
type Out;
}
trait Unapply {
type Out;
}
type Applied<F, T> = <(F, T) as Apply>::Out;
type Unapplied<T> = <T as Unapply>::Out;
trait Monad {
fn bind<T1, T2, F: FnOnce(T1) -> Applied<Self,T2>>(this: Applied<Self, T1>, f: F) -> Applied<Self, T2>;
fn then<T1, T2>(this: Applied<Self, T1>, rhs: Applied<Self, T2>) -> Applied<Self, T2> where (Self, T1): Apply, (Self, T2): Apply {
<Self as Monad>::bind::<T1, T2, _>(this, |_| rhs)
}
fn return_<T>(v: T) -> Applied<Self, T>;
}
trait MonadApplied<M: Monad, T1> where (M, T1): Apply {
fn bind<T2, F: FnOnce(T1) -> Applied<M, T2>>(self, f: F) -> Applied<M, T2> where (M, T2): Apply;
fn then<T2>(self, rhs: Applied<M, T2>) -> Applied<M, T2> where (M, T2): Apply;
}
impl<M: Monad, T1> MonadApplied<M, T1> for Applied<M, T1> where (M, T1): Apply {
fn bind<T2, F: FnOnce(T1) -> Applied<M, T2>>(self, f: F) -> Applied<M, T2> where (M, T2): Apply {
<M as Monad>::bind::<T1, T2, F>(self, f)
}
fn then<T2>(self, rhs: Applied<M, T2>) -> Applied<M, T2> where (M, T2): Apply {
<M as Monad>::then::<T1, T2>(self, rhs)
}
}
fn return_<M: Monad, T>(x: T) -> Applied<M, T> where (M, T): Apply {
<M as Monad>::return_::<T>(x)
}
#[allow(dead_code)]
struct Option_;
impl<T> Apply for (Option_, T) { type Out = Option<T>; }
impl<T> Unapply for Option<T> { type Out = Option_; }
impl Monad for Option_ {
fn bind<T1, T2, F: FnOnce(T1) -> Option<T2>>(this: Option<T1>, f: F) -> Option<T2> {
match this {
Some(x) => f(x),
None => None
}
}
fn return_<T>(v: T) -> Option<T> { Some(v) }
}
fn main() {
let x = return_(true).bind(|x| if x { Some(1usize) } else { None });
let y = return_(1usize).bind(|x| Some(x==2));
let z = return_(true).then(return_(false)); // No mention of the monad used. Should be an error!
println!("{:?}, {:?}, {:?}", x, y, z);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment