Skip to content

Instantly share code, notes, and snippets.

@hseeberger
Last active November 4, 2022 12:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hseeberger/b78338cbd39dc48fd9a7ea78ddc1be20 to your computer and use it in GitHub Desktop.
Save hseeberger/b78338cbd39dc48fd9a7ea78ddc1be20 to your computer and use it in GitHub Desktop.
Monad in Rust using GAT
trait Monad<A> {
type M<X>: Monad<X>;
fn unit(a: A) -> Self::M<A>;
fn bind<B, F>(self, f: F) -> Self::M<B>
where
F: FnMut(A) -> Self::M<B>;
}
impl<A> Monad<A> for Option<A> {
type M<X> = Option<X>;
fn unit(a: A) -> Self::M<A> {
Some(a)
}
fn bind<B, F>(self, f: F) -> Self::M<B>
where
F: FnMut(A) -> Self::M<B>,
{
self.and_then(f)
}
}
impl<A> Monad<A> for Vec<A> {
type M<X> = Vec<X>;
fn unit(a: A) -> Self::M<A> {
vec![a]
}
fn bind<B, F>(self, f: F) -> Self::M<B>
where
F: FnMut(A) -> Self::M<B>,
{
self.into_iter().flat_map(f).collect()
}
}
fn main() {
let bound_option =
unit_and_bind::<Option<_>, _, _, _>("Hello", |s| Some(format!("{s}, World!")));
println!("{bound_option:?}");
let bound_vec = unit_and_bind::<Vec<_>, _, _, _>(42, |n| vec![n - 1, n, n + 1]);
println!("{bound_vec:?}");
let option = Some("Hello");
let bound_option = bind::<_, _, String, _>(option, |s| Some(format!("{s}, World!")));
println!("{bound_option:?}");
let vec = vec![42];
let bound_vec = bind::<_, _, i32, _>(vec, |n| vec![n - 1, n, n + 1]);
println!("{bound_vec:?}");
}
fn unit_and_bind<M, A, B, F>(a: A, f: F) -> <<M as Monad<A>>::M<A> as Monad<A>>::M<B>
where
M: Monad<A>,
F: Fn(A) -> <<M as Monad<A>>::M<A> as Monad<A>>::M<B>,
{
let m = M::unit(a);
let mb = m.bind(f);
mb
}
fn bind<M, A, B, F>(m: M, f: F) -> <M as Monad<A>>::M<B>
where
M: Monad<A>,
F: Fn(A) -> <M as Monad<A>>::M<B>,
{
m.bind(f)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment