-
-
Save dylanede/3eaea1b0fa8901422add to your computer and use it in GitHub Desktop.
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