Created
July 6, 2015 11:25
-
-
Save anonymous/d33a969848c699b8cac4 to your computer and use it in GitHub Desktop.
Shared via Rust Playground
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//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