Skip to content

Instantly share code, notes, and snippets.

@dylanede
Forked from anonymous/playground.rs
Last active August 29, 2015 14:24
Show Gist options
  • Save dylanede/18ff4fece548eb859427 to your computer and use it in GitHub Desktop.
Save dylanede/18ff4fece548eb859427 to your computer and use it in GitHub Desktop.
//This trait is not used, but is useful for type equality constraints
trait ID {
type Out;
}
impl<T> ID for T {
type Out = T;
}
trait CanApply {
type Out: CanUnapply;
}
trait CanUnapply where (Self::F, Self::Arg): CanApply<Out=Self> {
type Arg;
type F;
}
type Apply<F, T> = <(F, T) as CanApply>::Out;
type UnapplyF<T> = <T as CanUnapply>::F;
type UnapplyArg<T> = <T as CanUnapply>::Arg;
type Reapply<FT1, T2> = Apply<UnapplyF<FT1>, T2>;
trait Monad {
fn bind<T1, T2, F: FnOnce(T1) -> Apply<Self,T2>>
(this: Apply<Self, T1>, f: F) -> Apply<Self, T2>;
fn then<T1, T2>(this: Apply<Self, T1>, rhs: Apply<Self, T2>) -> Apply<Self, T2>
where (Self, T1): CanApply, (Self, T2): CanApply
{
<Self as Monad>::bind::<T1, T2, _>(this, |_| rhs)
}
fn return_<T>(v: T) -> Apply<Self, T>;
}
trait MonadApplied<M: Monad, T1> {
type M: Monad = M;
type T1 = T1;
fn bind<T2, F: FnOnce(T1) -> Apply<M, T2>>
(self, f: F) -> Apply<M, T2>
where (M, T2): CanApply;
fn then<T2>(self, rhs: Apply<M, T2>) -> Apply<M, T2>
where (M, T2): CanApply;
}
impl<FT1: CanUnapply> MonadApplied<UnapplyF<FT1>, UnapplyArg<FT1>>
for FT1
where
UnapplyF<FT1>: Monad,
// This next constraint should not be necessary - see definition
// of CanUnapply
(UnapplyF<FT1>, UnapplyArg<FT1>): CanApply<Out=FT1>
{
fn bind<T2, F: FnOnce(Self::T1) -> Apply<Self::M, T2>>
(self, f: F) -> Apply<Self::M, T2>
where (UnapplyF<FT1>, T2): CanApply
{
Self::M::bind::<Self::T1, T2, F>(self, f)
}
fn then<T2>(self, rhs: Apply<Self::M, T2>) -> Apply<Self::M, T2>
where (Self::M, T2): CanApply
{
Self::M::then::<Self::T1, T2>(self, rhs)
}
}
fn return_<FT1: CanUnapply>(v: UnapplyArg<FT1>) -> FT1
where
UnapplyF<FT1>: Monad,
// Again, this next constraint should not be needed
(UnapplyF<FT1>, UnapplyArg<FT1>): CanApply<Out=FT1>
{
<UnapplyF<FT1> as Monad>::return_::<UnapplyArg<FT1>>(v)
}
#[allow(dead_code)]
struct Option_;
impl<T> CanApply for (Option_, T) { type Out = Option<T>; }
impl<T> CanUnapply for Option<T> { type Arg = T; type F = 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) }
}
#[derive(Debug)]
enum MyOption<T> {
Some(T),
None
}
#[allow(dead_code)]
struct MyOption_;
impl<T> CanApply for (MyOption_, T) { type Out = MyOption<T>; }
impl<T> CanUnapply for MyOption<T> { type Arg = T; type F = MyOption_; }
impl Monad for MyOption_ {
fn bind<T1, T2, F: FnOnce(T1) -> MyOption<T2>>(this: MyOption<T1>, f: F) -> MyOption<T2> {
match this {
MyOption::Some(x) => f(x),
MyOption::None => MyOption::None
}
}
fn return_<T>(v: T) -> MyOption<T> { MyOption::Some(v) }
}
fn main() {
let x = return_::<Option<_>>(true).bind(|x| if x { Some(1usize) } else { None });
let y = Option_::return_(1usize).bind(|x| Some(x==2));
let z: MyOption<_> = return_(true);//.then(MyOption_::return_(false));
println!("{:?}, {:?}, {:?}", x, y, z);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment