trait Kind<T> {
    type Make;
}

enum OptionKind {}

impl<T> Kind<T> for OptionKind {
    type Make = Option<T>;
}

trait FunctorKind<A, B>: Kind<A> + Kind<B> {
    fn fmapk(<Self as Kind<A>>::Make, impl Fn(A) -> B) -> <Self as Kind<B>>::Make;
}

impl<A, B> FunctorKind<A, B> for OptionKind {
    fn fmapk(me: Option<A>, f: impl Fn(A) -> B) -> Option<B> {
        match me {
            Some(m) => Some(f(m)),
            None => None,
        }
    }
}

trait Functor<A, B>: Sized {
    type Kind: FunctorKind<A, B>;
    //type Item;
    fn fmap(my: <Self::Kind as Kind<A>>::Make, f: impl Fn(A) -> B) -> <Self::Kind as Kind<B>>::Make {
        Self::Kind::fmapk(my, f)
    }
}

impl<A, B> Functor<A, B> for Option<A> {
    type Kind = OptionKind;
}

fn main() {
    println!("{:?}", OptionKind::fmapk(Some(10), |a| a + 1));
    println!("{:?}", Option::fmap(Some(10), |a| a + 1));
}