use crate::*;
pub type App<P, A> = <P as Pred>::Out<A>;
pub type App2<P, A, B> = <P as Pred>::Out<And<A, B>>;
pub trait Pred: 'static + Clone {
type Out<A: Prop>: Prop;
}
pub trait Reflexivity: Pred {
fn refl<A: Prop>(&self) -> Self::Out<And<A, A>>;
}
pub trait Irreflexivity: Pred {
fn irrefl<A: Prop>(&self) -> Not<Self::Out<And<A, A>>>;
}
pub trait Symmetry: Pred {
fn symmetry<A: Prop, B: Prop>(&self) -> Imply<App2<Self, A, B>, App2<Self, B, A>>;
}
pub trait Antisymmetry: Pred {
fn antisymmetry<A: Prop, B: Prop>(&self) ->
Imply<And<App2<Self, A, B>, App2<Self, B, A>>, Eq<A, B>>;
}
pub trait Asymmetry: Pred {
fn asymmetry<A: Prop, B: Prop>(&self) -> Imply<App2<Self, A, B>, Not<App2<Self, B, A>>>;
}
pub trait Transitivity: Pred {
fn transitivity<A: Prop, B: Prop, C: Prop>(&self) ->
Imply<And<App2<Self, A, B>, App2<Self, B, C>>, App2<Self, A, C>>;
}
pub trait Connectivity: Pred {
fn connectivity<A: Prop, B: Prop>(&self) ->
Imply<Not<Eq<A, B>>, Or<App2<Self, A, B>, App2<Self, B, A>>>;
}
pub trait StrongConnectivity: Pred {
fn strong_connectivity<A: Prop, B: Prop>(&self) -> Or<App2<Self, A, B>, App2<Self, B, A>>;
}
pub trait All<P: Pred>: Prop {
fn all<A: Prop>(&self) -> App<P, A>;
}
#[derive(Clone)]
pub struct PImply<B: Pred, C: Pred>(std::marker::PhantomData<(B, C)>);
impl<B: Pred, C: Pred> Pred for PImply<B, C> {
type Out<A: Prop> = Imply<App<B, A>, App<C, A>>;
}
impl<P: Pred> All<PImply<P, P>> for () {
fn all<A: Prop>(&self) -> Imply<App<P, A>, App<P, A>> {
Rc::new(move |pa| pa)
}
}
pub trait Any<B: Pred>: Prop {
fn any<C: Pred>(&self, f: impl All<PImply<B, C>>) -> C;
}
#[derive(Clone)]
pub struct Singleton<X: Prop>(pub X);
impl<X: Prop> Pred for Singleton<X> {
type Out<A: Prop> = X;
}