Skip to content

Instantly share code, notes, and snippets.

@rust-play
Created February 10, 2021 15:11
Show Gist options
  • Save rust-play/39bffcf6f0374b1a6722d41b50986d9c to your computer and use it in GitHub Desktop.
Save rust-play/39bffcf6f0374b1a6722d41b50986d9c to your computer and use it in GitHub Desktop.
Code shared from the Rust Playground
/// Warning: the following code is made for experiment.
/// If you cause losses due to the use of this code in production, I am not responsible.
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct List<T = ()>(pub Vec<T>);
#[derive(PartialEq, Eq, Clone, Debug)]
pub struct Id<T = ()>(pub T);
pub trait HKT<T> {
type Actual;
}
pub type Apply<H, T> = <H as HKT<T>>::Actual;
impl<T> HKT<T> for List {
type Actual = List<T>;
}
impl<T> HKT<T> for Id {
type Actual = Id<T>;
}
pub trait Monad<T>: HKT<T> {
fn ret(value: T) -> Apply<Self, T>;
fn bind<R>(value: Apply<Self, T>, f: &dyn Fn(T) -> Apply<Self, R>) -> Apply<Self, R>
where
Self: HKT<R>;
}
impl List {
fn bind_impl<T, R>(value: Apply<Self, T>, f: &dyn Fn(T) -> Apply<Self, R>) -> Apply<Self, R> {
let mut result = vec![];
for v in value.0.into_iter() {
for v in f(v).0.into_iter() {
result.push(v);
}
}
List(result)
}
}
impl<T: Clone> Monad<T> for List {
fn ret(value: T) -> Apply<Self, T> {
List(vec![value])
}
/// The bind method cannot be directly implemented due to a weird compilation error.
fn bind<R>(value: Apply<Self, T>, f: &dyn Fn(T) -> Apply<Self, R>) -> Apply<Self, R>
where
Self: HKT<R>,
{
Self::bind_impl::<T, R>(value, f)
}
}
impl Id {
fn bind_impl<T, R>(value: Apply<Self, T>, f: &dyn Fn(T) -> Apply<Self, R>) -> Apply<Self, R> {
f(value.0)
}
}
impl<T> Monad<T> for Id {
fn ret(value: T) -> Apply<Self, T> {
Id(value)
}
fn bind<R>(value: Apply<Self, T>, f: &dyn Fn(T) -> Apply<Self, R>) -> Apply<Self, R>
where
Self: HKT<R>,
{
Self::bind_impl::<T, R>(value, f)
}
}
pub fn lift2<T: Clone, R, H: Monad<T> + Monad<R> + Monad<(T, R)>>(
v1: Apply<H, T>,
v2: Apply<H, R>,
) -> Apply<H, (T, R)>
where
Apply<H, R>: Clone,
{
<H as Monad<T>>::bind::<(T, R)>(v1, &|v1| {
<H as Monad<R>>::bind::<(T, R)>(v2.clone(), &|v2| {
<H as Monad<(T, R)>>::ret((v1.clone(), v2))
})
})
}
fn main() {
assert_eq!(lift2::<_, _, Id>(Id(0), Id("")), Id((0, "")));
assert_eq!(
lift2::<_, _, List>(List(vec![0, 1, 2]), List(vec!["", "1", "2"])),
List(vec![
(0, ""),
(0, "1"),
(0, "2"),
(1, ""),
(1, "1"),
(1, "2"),
(2, ""),
(2, "1"),
(2, "2")
])
);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment