Skip to content

Instantly share code, notes, and snippets.

@bodil
Last active January 28, 2019 22:52
Show Gist options
  • Save bodil/cb7c7df5dbe3ac8da15d26a563f55928 to your computer and use it in GitHub Desktop.
Save bodil/cb7c7df5dbe3ac8da15d26a563f55928 to your computer and use it in GitHub Desktop.
Who needs higher kinded types anyway
trait Higher<A, B> {
type Target;
}
trait Higher3<A, B, C> {
type Target2;
type Target3;
}
impl<A, B> Higher<A, B> for Option<A> {
type Target = Option<B>;
}
impl<A, B, E> Higher<A, B> for Result<A, E> {
type Target = Result<B, E>;
}
impl<A, B> Higher<A, B> for Vec<A> {
type Target = Vec<B>;
}
impl<A, B, C> Higher3<A, B, C> for Option<A> {
type Target2 = Option<B>;
type Target3 = Option<C>;
}
impl<A, B, C, E> Higher3<A, B, C> for Result<A, E> {
type Target2 = Result<B, E>;
type Target3 = Result<C, E>;
}
impl<A, B, C> Higher3<A, B, C> for Vec<A> {
type Target2 = Vec<B>;
type Target3 = Vec<C>;
}
trait Functor<A, B>: Higher<A, B> {
fn map<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> B;
}
impl<A, B> Functor<A, B> for Option<A> {
fn map<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> B,
{
self.map(f)
}
}
impl<A, B, E> Functor<A, B> for Result<A, E> {
fn map<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> B,
{
self.map(f)
}
}
impl<A, B> Functor<A, B> for Vec<A> {
fn map<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> B,
{
self.into_iter().map(f).collect()
}
}
trait Applicative<A, B, C>: Functor<A, C> + Higher3<A, B, C>
where
B: Fn(A) -> C,
{
fn ap(self, f: <Self as Higher3<A, B, C>>::Target2) -> <Self as Higher3<A, B, C>>::Target3;
}
impl<A, B, C> Applicative<A, B, C> for Option<A>
where
B: Fn(A) -> C,
{
fn ap(self, f: <Self as Higher3<A, B, C>>::Target2) -> <Self as Higher3<A, B, C>>::Target3 {
self.and_then(|v| f.map(|f| f(v)))
}
}
impl<A, B, C, E> Applicative<A, B, C> for Result<A, E>
where
B: Fn(A) -> C,
{
fn ap(self, f: <Self as Higher3<A, B, C>>::Target2) -> <Self as Higher3<A, B, C>>::Target3 {
self.and_then(|v| f.map(|f| f(v)))
}
}
impl<A, B, C> Applicative<A, B, C> for Vec<A>
where
A: Clone,
B: Fn(A) -> C + Clone,
{
fn ap(self, f: <Self as Higher3<A, B, C>>::Target2) -> <Self as Higher3<A, B, C>>::Target3 {
self.bind(|v| f.clone().map(|f2| f2(v.clone())))
}
}
trait Monad<A, B>: Functor<A, B> {
fn bind<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> <Self as Higher<A, B>>::Target;
}
impl<A, B> Monad<A, B> for Option<A> {
fn bind<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> <Self as Higher<A, B>>::Target,
{
self.and_then(f)
}
}
impl<A, B, E> Monad<A, B> for Result<A, E> {
fn bind<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> <Self as Higher<A, B>>::Target,
{
self.and_then(f)
}
}
impl<A, B> Monad<A, B> for Vec<A> {
fn bind<F>(self, f: F) -> <Self as Higher<A, B>>::Target
where
F: Fn(A) -> <Self as Higher<A, B>>::Target,
{
self.into_iter().flat_map(|v| f(v).into_iter()).collect()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn flatmap_that_shit() {
assert_eq!(
Some("1337".to_string()),
Some(1337).bind(|n| Some(format!("{}", n)))
);
assert_eq!(vec![1, 1, 2, 2, 3, 3], vec![1, 2, 3].bind(|v| vec![v, v]))
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment