Skip to content

Instantly share code, notes, and snippets.

@KeenS
Last active July 10, 2017 02:42
Show Gist options
  • Save KeenS/9665e098ade28fdcaf42bb77b9940c23 to your computer and use it in GitHub Desktop.
Save KeenS/9665e098ade28fdcaf42bb77b9940c23 to your computer and use it in GitHub Desktop.
// a parameterized monad
mod idx {
use std::marker::PhantomData;
#[derive(Debug)]
pub struct Idx<X, Y, A>
{
x: A,
pre: PhantomData<X>,
post: PhantomData<Y>,
}
impl <X, Y, A>Idx<X, Y, A>
{
pub fn new(a: A) -> Self {
Idx {
x: a,
pre: PhantomData,
post: PhantomData,
}
}
pub fn bind<Z, U, F>(&self, f: F) -> Idx<X, Z, U>
where F: Fn(&A) -> Idx<Y, Z, U>,
{
let pre = self.pre;
let r = f(&self.x);
Idx{x:r.x, pre:pre, post:r.post}
}
}
impl <X, T>Idx<X, X, T>
{
pub fn ret(x: T) -> Idx<X, X, T> {
Idx{x:x, pre:PhantomData, post:PhantomData}
}
}
impl <T>Idx<(), (), T>
{
pub fn run(&self) -> &T {
&self.x
}
}
}
mod idx_sample {
use idx::Idx;
pub struct One;
pub struct Two;
pub fn op0to1<T>(x : T) -> Idx<(), One, T> {
Idx::new(x)
}
pub fn op1to2<T>(x : T) -> Idx<One, Two, T> {
Idx::new(x)
}
pub fn op2to0<T>(x : T) -> Idx<Two, (), T> {
Idx::new(x)
}
}
// https://github.com/TeXitoi/rust-mdo/blob/9b5f44e4159e4587afe14f5d3d99e475022b0959/src/lib.rs#L48-L90
macro_rules! mdo {
(
let $p: pat = $e: expr ; $( $t: tt )*
) => (
{ let $p = $e ; mdo! { $( $t )* } }
);
(
let $p: ident : $ty: ty = $e: expr ; $( $t: tt )*
) => (
{ let $p: $ty = $e ; mdo! { $( $t )* } }
);
(
$p: pat =<< $e: expr ; $( $t: tt )*
) => (
$e.bind(|$p| mdo! { $( $t )* } )
);
(
$p: ident : $ty: ty =<< $e: expr ; $( $t: tt )*
) => (
$e.bind(|$p : $ty| mdo! { $( $t )* } )
);
(
ign $e: expr ; $( $t: tt )*
) => (
$e.bind(|_| mdo! { $( $t )* })
);
(
when $e: expr ; $( $t: tt )*
) => (
(if $e { ret(()) } else { mzero() }).bind(|_| mdo! { $( $t )* })
);
(
ret $f: expr
) => (
$f
)
}
fn main() {
use idx::Idx;
use idx_sample::{op0to1, op1to2, op2to0};
let m = || mdo! {
z =<< Idx::ret(10);
x =<< Idx::ret(20);
ret Idx::ret(z+x)
};
println!("{:?}", m().run());
let m2 = mdo! {
z =<< op0to1(123);
x =<< op1to2(345);
ign (op2to0(()));
ret Idx::ret(z * x)
};
println!("{:?}", m2.run());
let m3 = mdo! {
z =<< op0to1(123);
x =<< op1to2(345);
ign (op2to0(()));
ret Idx::ret(z * x * x)
};
println!("{:?}", m3.run());
// let m = mdo! {
// z =<< op0to1(123);
// x =<< op2to0(345); // ERROR
// ret Idx::ret(z * x)
// };
// error[E0308]: mismatched types
// --> main.rs:137:15
// |
// 135 | let m = mdo! {
// | - in this macro invocation
// 136 | z =<< op0to1(123);
// 137 | x =<< op2to0(345); // ERROR
// | ^^^^^^^^^^^ expected struct `idx::One`, found struct `idx::Two`
// |
// = note: expected type `idx::Idx<'_, idx::One, _, _>`
// = note: found type `idx::Idx<'_, idx::Two, (), {integer}>`
// error: aborting due to previous error
// let m3 = mdo! {
// z =<< op0to1(123);
// x =<< op1to2(345);
// ign m(); // ERROR: m is monomorphic
// ign (op2to0(()));
// ret Idx::ret(z * x)
// };
// println!("{:?}", m2.run());
// error[E0308]: mismatched types
// --> main.rs:111:13
// |
// 108 | let m3 = mdo! {
// | - in this macro invocation
// ...
// 111 | ign m(); // ERROR: m is monomorphic
// | ^^^ expected struct `idx::Two`, found ()
// |
// = note: expected type `idx::Idx<'_, idx::Two, _, _>`
// = note: found type `idx::Idx<'_, (), (), {integer}>`
// error: aborting due to previous error
}
@KeenS
Copy link
Author

KeenS commented Dec 8, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment