Skip to content

Instantly share code, notes, and snippets.

@srijs
Last active September 3, 2019 13:35
Show Gist options
  • Save srijs/99f25e8c931bd3519587 to your computer and use it in GitHub Desktop.
Save srijs/99f25e8c931bd3519587 to your computer and use it in GitHub Desktop.
use std::boxed::Box;
use std::option::Option;
use std::result::Result;
pub trait Functor<'a, A, B, F: Fn(&'a A) -> B> {
type Output;
fn fmap(&'a self, f: F) -> Self::Output;
}
pub fn fmap<'a, A, B, X: Functor<'a, A, B, F>, F: Fn(&'a A) -> B>(x: &'a X, f: F) -> X::Output {
x.fmap(f)
}
impl<'a, A, B, F: Fn(&'a A) -> B> Functor<'a, A, B, F> for Box<A> {
type Output = Box<B>;
fn fmap(&'a self, f: F) -> Box<B> {
Box::new(f(&**self))
}
}
impl<'a, A, B, F: Fn(&'a A) -> B> Functor<'a, A, B, F> for Option<A> {
type Output = Option<B>;
fn fmap(&'a self, f: F) -> Option<B> {
self.as_ref().map(|x| f(&x))
}
}
impl<'a, A, B, E: Copy, F: Fn(&'a A) -> B> Functor<'a, A, B, F> for Result<A, E> {
type Output = Result<B, E>;
fn fmap(&'a self, f: F) -> Result<B, E> {
match *self {
Ok(ref x) => Ok(f(x)),
Err(e) => Err(e)
}
}
}
#[test]
fn it_works_with_box() {
let ax = Box::new(0);
let bx = fmap(&ax, |a| a + 1);
let cx = fmap(&ax, |a| a + 2);
assert_eq!(bx, Box::new(1));
assert_eq!(cx, Box::new(2));
}
#[test]
fn it_works_with_option() {
let ax = Option::Some(0);
let bx = fmap(&ax, |a| a + 1);
let cx = fmap(&ax, |a| a + 2);
assert_eq!(bx, Option::Some(1));
assert_eq!(cx, Option::Some(2));
}
#[test]
fn it_works_with_result() {
let ax: Result<_, ()> = Result::Ok(0);
let bx = fmap(&ax, |a| a + 1);
let cx = fmap(&ax, |a| a + 2);
assert_eq!(bx, Result::Ok(1));
assert_eq!(cx, Result::Ok(2));
}
@bangedorrunt
Copy link

Thank you @srijs for great example, I just made a little change to make the snippet run because current one makes compiler complain about error: the parameter typeAmay not live long enough [E0309]

Please see the diff

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment