Skip to content

Instantly share code, notes, and snippets.

@kyleheadley
Last active February 8, 2017 18:20
Show Gist options
  • Save kyleheadley/3b0010af2a05692cbb68f0d1f3e1b108 to your computer and use it in GitHub Desktop.
Save kyleheadley/3b0010af2a05692cbb68f0d1f3e1b108 to your computer and use it in GitHub Desktop.
Prototype implementation of Monads in Rust
use std::fmt::Display;
trait Monadic {}
#[derive(Debug)]
struct Monad<M:Monadic,T>(M,T);
#[derive(Debug)]
struct Opt(bool);
impl Monadic for Opt {}
impl<T:Default> Monad<Opt,T> {
fn ret(t:T) -> Self {
Monad(Opt(true),t)
}
fn bind<F,U:Default>(self,f:F) -> Monad<Opt,U> where
F: FnOnce(T) -> Monad<Opt,U>
{
let Monad(Opt(is_some),val) = self;
if is_some { f(val) } else { Monad(Opt(false),Default::default()) }
}
fn none() -> Self { Monad(Opt(false),Default::default())}
}
#[derive(Debug)]
struct Log(String);
impl Monadic for Log {}
impl<T:Display> Monad<Log,T> {
fn ret(t:T) -> Self {
Monad(Log(format!("{}",t)),t)
}
fn bind<F,U>(self,f:F) -> Monad<Log,U> where
F: FnOnce(T) -> Monad<Log,U>
{
let Monad(Log(old_log),val) = self;
let Monad(Log(new_log),val) = f(val);
Monad(Log(format!("{},{}",old_log,new_log)),val)
}
}
fn main() {
let just3 = Monad::<Opt,_>::ret(3);
println!("{:?}",just3);
let just4 = just3.bind(|x|Monad::<Opt,_>::ret(x+1));
println!("{:?}",just4);
let nope = Monad::<Opt,usize>::none();
let nope2 = nope.bind(|x|Monad::<Opt,_>::ret(x+1));
println!("{:?}",nope2);
let nope3 = just4.bind(|_|Monad::<_,usize>::none());
println!("{:?}",nope3);
let nope = Monad::<Opt,usize>::none();
let nope4 = nope.bind(|x|Monad::<Opt,_>::ret(format!("{}",x)));
println!("{:?}",nope4);
let just5 = Monad::<Opt,_>::ret(5);
let str5 = just5.bind(|x|Monad::<Opt,_>::ret(format!("{}",x)));
println!("{:?}",str5);
let logone = Monad::<Log,_>::ret(1);
let logtwo = logone.bind(|x|Monad::<Log,_>::ret(x+1));
let loghuh = logtwo.bind(|_|Monad::<Log,_>::ret("huh"));
let logpi = loghuh.bind(|_|Monad::<Log,_>::ret(3.14159));
let logtau = logpi.bind(|p|Monad::<Log,_>::ret(p*2.0));
let logdub = logtau.bind(|_|Monad::<Log,_>::ret("once").bind(|_|Monad::<Log,_>::ret("twice")));
print!("{:?}", logdub);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment