use std::rc::Rc;
use std::sync::Arc;
pub unsafe trait Equals<T> {
fn eqcast(self) -> T;
}
unsafe impl<T> Equals<T> for T {
fn eqcast(self) -> T { self }
}
pub trait Generic1 {
type Type;
}
pub trait Rebind1<Y> : Generic1 {
type Type;
}
pub trait Generic2: Generic1 {
type Type;
}
pub trait Rebind2<Y> : Generic2 {
type Type;
}
pub trait Functor : Generic1 {
fn fmap<Y, F: Fn(<Self as Generic1>::Type)->Y>(self, f: F) -> <Self as Rebind1<Y>>::Type where Self: Rebind1<Y>;
}
pub trait Monad: Functor {
fn unit(value: <Self as Generic1>::Type) -> Self;
fn bind<U, F: Fn(<Self as Generic1>::Type) -> <Self as Rebind1<U>>::Type>(self, f: F) -> <Self as Rebind1<U>>::Type where Self: Rebind1<U>;
fn join<U>(self) -> <Self as Rebind1<U>>::Type where <Self as Generic1>::Type: Equals<<Self as Rebind1<U>>::Type>, Self: Rebind1<U> + Sized { self.bind(|x|x.eqcast()) }
}
pub trait BinaryOperation<T> {
fn apply(lhs: T, rhs: T) -> T;
}
pub trait AssociativeOperation<T> : BinaryOperation<T> {}
pub trait Magma<T: BinaryOperation<Self>>: Sized {}
impl<T, Op> Magma<Op> for T where Op: BinaryOperation<T> {}
pub trait Semigroup<T: AssociativeOperation<Self>> : Magma<T> {}
impl<T, Op> Semigroup<Op> for T where Op: AssociativeOperation<T> {}
pub trait Monoid<T: AssociativeOperation<Self>> : Semigroup<T> {
fn one() -> Self;
}
macro_rules! generic1 {
($x:ident) => {
impl<T> Generic1 for $x<T> {
type Type = T;
}
impl<T, Y> Rebind1<Y> for $x<T> where $x<T>: Generic1<Type=T> {
type Type = $x<Y>;
}
};
}
macro_rules! generic2 {
($x:ident) => {
impl<T0, T1> Generic1 for $x<T0, T1> {
type Type = T0;
}
impl<T0, T1, Y> Rebind1<Y> for $x<T0, T1> where $x<T0, T1>: Generic1<Type=T0>, $x<T0, T1>: Generic2<Type=T1> {
type Type = $x<Y, T1>;
}
impl<T0, T1> Generic2 for $x<T0, T1> where $x<T0, T1>: Generic1<Type=T0> {
type Type = T1;
}
impl<T0, T1, Y> Rebind2<Y> for $x<T0, T1> where $x<T0, T1>: Generic1<Type=T0>, $x<T0, T1>: Generic2<Type=T1> {
type Type = $x<T0, Y>;
}
};
}
generic1!(Option);
generic2!(Result);
generic1!(Vec);
impl<'a, X, T> Generic1 for &'a X where X: Generic1<Type=T> {
type Type = T;
}
impl<'a, X, Y, T> Rebind1<Y> for &'a X where X: Rebind1<Y, Type=T> {
type Type = T;
}
impl<'a, X, T> Generic2 for &'a X where X: Generic2<Type=T> {
type Type = T;
}
impl<'a, X, Y, T> Rebind2<Y> for &'a X where X: Rebind2<Y, Type=T> {
type Type = T;
}
macro_rules! generic_refs {
($x:ident) => {
impl<X, T> Generic1 for $x<X> where X: Generic1<Type=T> {
type Type = T;
}
impl<X, Y, T> Rebind1<Y> for $x<X> where X: Rebind1<Y, Type=T> {
type Type = T;
}
impl<X, T> Generic2 for $x<X> where X: Generic2<Type=T> {
type Type = T;
}
impl<X, Y, T> Rebind2<Y> for $x<X> where X: Rebind2<Y, Type=T> {
type Type = T;
}
};
}
generic_refs!(Box);
generic_refs!(Rc);
generic_refs!(Arc);
impl<T> Functor for Option<T> {
fn fmap<Y, F: Fn(<Option<T> as Generic1>::Type)->Y>(self, f: F) -> <Option<T> as Rebind1<Y>>::Type {
match self {
Some(value) => Some(f(value)),
None => None
}
}
}
impl<T> Monad for Option<T> {
fn unit(value: T) -> Option<T> { Some(value) }
fn bind<U, F: Fn(<Option<T> as Generic1>::Type) -> <Option<T> as Rebind1<U>>::Type>(self, f: F) -> <Option<T> as Rebind1<U>>::Type {
match self {
Some(value) => f(value),
None => None
}
}
fn join<U>(self) -> <Option<T> as Rebind1<U>>::Type where <Option<T> as Generic1>::Type: Equals<<Option<T> as Rebind1<U>>::Type> {
match self {
Some(value) => value.eqcast(),
None => None
}
}
}
impl<T, E> Functor for Result<T, E> {
fn fmap<Y, F: Fn(<Result<T, E> as Generic1>::Type)->Y>(self, f: F) -> <Result<T, E> as Rebind1<Y>>::Type {
match self {
Ok(value) => Ok(f(value)),
Err(e) => Err(e)
}
}
}
impl<T> Functor for Vec<T> {
fn fmap<Y, F: Fn(<Vec<T> as Generic1>::Type)->Y>(self, f: F) -> <Vec<T> as Rebind1<Y>>::Type { self.into_iter().map(f).collect() }
}
pub struct Add;
impl<T: std::ops::Add<Output=T>> BinaryOperation<T> for Add {
fn apply(lhs: T, rhs: T) -> T { lhs + rhs }
}
impl AssociativeOperation<isize> for Add {}
impl AssociativeOperation<i8> for Add {}
impl AssociativeOperation<i16> for Add {}
impl AssociativeOperation<i32> for Add {}
impl AssociativeOperation<i64> for Add {}
impl AssociativeOperation<u16> for Add {}
impl AssociativeOperation<u32> for Add {}
impl AssociativeOperation<u64> for Add {}
pub struct Mul;
impl<T: std::ops::Mul<Output=T>> BinaryOperation<T> for Mul {
fn apply(lhs: T, rhs: T) -> T { lhs * rhs }
}
impl AssociativeOperation<isize> for Mul {}
impl AssociativeOperation<i8> for Mul {}
impl AssociativeOperation<i16> for Mul {}
impl AssociativeOperation<i32> for Mul {}
impl AssociativeOperation<i64> for Mul {}
impl AssociativeOperation<usize> for Mul {}
impl AssociativeOperation<u8> for Mul {}
impl AssociativeOperation<u16> for Mul {}
impl AssociativeOperation<u32> for Mul {}
impl AssociativeOperation<u64> for Mul {}
pub struct Concat;
impl<U, T: IntoIterator<Item=U> + std::iter::FromIterator<U>> BinaryOperation<T> for Concat {
fn apply(lhs: T, rhs: T) -> T { lhs.into_iter().chain(rhs.into_iter()).collect() }
}
impl<U, T: IntoIterator<Item=U> + std::iter::FromIterator<U>> AssociativeOperation<T> for Concat {}
impl<U, T> Monoid<Concat> for T where T: std::iter::FromIterator<U> + IntoIterator<Item=U> {
fn one() -> T {
<T as std::iter::FromIterator<U>>::from_iter(std::iter::empty())
}
}
#[test]
fn it_works() {
let x = Some(1);
let f1 = |x|Some(x*2);
let f2 = |x|Some(x*2);
assert!(x.fmap(f1).join() == x.bind(f2));
let x = Some(Some(1));
assert!(x.bind(|x|x) == x.join());
}