Skip to content

Instantly share code, notes, and snippets.

@StephenWakely
Last active November 3, 2022 23:19
Show Gist options
  • Save StephenWakely/f64415a970b0c3abc30777886c6a8cb4 to your computer and use it in GitHub Desktop.
Save StephenWakely/f64415a970b0c3abc30777886c6a8cb4 to your computer and use it in GitHub Desktop.
Monads in Rust
trait Monad<A> {
type Res<B>;
fn pure(item: A) -> Self;
fn bind<B, F: Fn(&A) -> Self::Res<B>>(&self, f: F) -> Self::Res<B>;
}
impl<A> Monad<A> for Option<A> {
type Res<B> = Option<B>;
fn bind<B, F: Fn(&A) -> Self::Res<B>>(&self, f: F) -> Self::Res<B> {
match self {
Some(a) => f(a),
None => None,
}
}
fn pure(item: A) -> Self {
Some(item)
}
}
impl<A> Monad<A> for Vec<A> {
type Res<B> = Vec<B>;
fn bind<B, F: Fn(&A) -> Self::Res<B>>(&self, f: F) -> Self::Res<B> {
self.iter().map(f).flatten().collect()
}
fn pure(item: A) -> Self {
vec![item]
}
}
fn double_string<F, G>(param: F) -> G
where
F: Monad<usize, Res<String> = G>,
G: Monad<String>,
{
param.bind::<String, _>(|num| G::pure((num * 2).to_string()))
}
fn main() {
println!("{:?}", double_string(Some(32)));
// >> Some("64")
println!("{:?}", double_string(None));
// >> None
println!("{:?}", double_string(vec![1, 2, 3]));
// >> ["2", "4", "6"]
// Use the list monad to create ambiguous computations - ones that return multiple results..
println!("{:?}", vec![1, 2, 3].bind(|a| vec![*a, *a * 2, *a * 3]));
// >> [1, 2, 3, 2, 4, 6, 3, 6, 9]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment