use super::peano::{Aequus, Maior, Minor, MinorVelAequus, Naturalis, NonNihil};
use core::marker::PhantomData;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Testimonium<T, P: ?Sized> {
_type: PhantomData<T>,
_property: PhantomData<P>,
}
#[inline]
pub fn testimonium<T, P: ?Sized>() -> Testimonium<T, P>
where
T: TestimoniumConstructor<P>,
{
Testimonium {
_type: PhantomData,
_property: PhantomData,
}
}
pub trait TestimoniumConstructor<P: ?Sized> {}
pub struct IsNonNihil;
pub struct IsMinor<M>(PhantomData<M>);
pub struct IsMaior<M>(PhantomData<M>);
pub struct IsAequus<M>(PhantomData<M>);
pub struct IsMinorVelAequus<M>(PhantomData<M>);
impl<N: NonNihil> TestimoniumConstructor<IsNonNihil> for N {}
impl<N: Naturalis + Minor<M>, M: Naturalis> TestimoniumConstructor<IsMinor<M>> for N {}
impl<N: Naturalis + Maior<M>, M: Naturalis> TestimoniumConstructor<IsMaior<M>> for N {}
impl<N: Naturalis + Aequus<M>, M: Naturalis> TestimoniumConstructor<IsAequus<M>> for N {}
impl<N: Naturalis + MinorVelAequus<M>, M: Naturalis> TestimoniumConstructor<IsMinorVelAequus<M>>
for N
{
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Verum;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Falsum {}
pub trait Propositio {
const VALUE: bool;
}
impl Propositio for Verum {
const VALUE: bool = true;
}
impl Propositio for Falsum {
const VALUE: bool = false;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Aequalitas<A, B> {
_a: PhantomData<A>,
_b: PhantomData<B>,
}
impl<A> Aequalitas<A, A> {
#[inline]
pub fn reflexio() -> Self {
Aequalitas {
_a: PhantomData,
_b: PhantomData,
}
}
}
impl<A, B> Aequalitas<A, B> {
#[inline]
pub fn symmetria(self) -> Aequalitas<B, A> {
Aequalitas {
_a: PhantomData,
_b: PhantomData,
}
}
#[inline]
pub fn transitivitas<C>(self, _other: Aequalitas<B, C>) -> Aequalitas<A, C> {
Aequalitas {
_a: PhantomData,
_b: PhantomData,
}
}
#[inline]
pub fn congruentia<F: crate::typeclasses::hkt::HKT>(
self,
) -> Aequalitas<F::Target<A>, F::Target<B>> {
Aequalitas {
_a: PhantomData,
_b: PhantomData,
}
}
}
#[inline]
pub fn reflexio<A>() -> Aequalitas<A, A> {
Aequalitas::reflexio()
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Decisio<P> {
Ita(P),
Non,
}
impl<P> Decisio<P> {
#[inline]
pub fn is_ita(&self) -> bool {
matches!(self, Decisio::Ita(_))
}
#[inline]
pub fn is_non(&self) -> bool {
matches!(self, Decisio::Non)
}
#[inline]
pub fn map<Q, F>(self, f: F) -> Decisio<Q>
where
F: FnOnce(P) -> Q,
{
match self {
Decisio::Ita(p) => Decisio::Ita(f(p)),
Decisio::Non => Decisio::Non,
}
}
#[inline]
pub fn unwrap(self) -> P {
match self {
Decisio::Ita(p) => p,
Decisio::Non => panic!("Called unwrap on Decisio::Non"),
}
}
#[inline]
pub fn expect(self, msg: &str) -> P {
match self {
Decisio::Ita(p) => p,
Decisio::Non => panic!("{}", msg),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Existentia<T, P> {
pub witness: T,
pub proof: P,
}
impl<T, P> Existentia<T, P> {
#[inline]
pub fn new(witness: T, proof: P) -> Self {
Existentia { witness, proof }
}
#[inline]
pub fn fst(self) -> T {
self.witness
}
#[inline]
pub fn snd(self) -> P {
self.proof
}
#[inline]
pub fn map_witness<U, F>(self, f: F) -> Existentia<U, P>
where
F: FnOnce(T) -> U,
{
Existentia {
witness: f(self.witness),
proof: self.proof,
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub struct Coniunctio<P, Q> {
pub sinister: P,
pub dexter: Q,
}
impl<P, Q> Coniunctio<P, Q> {
#[inline]
pub fn new(p: P, q: Q) -> Self {
Coniunctio {
sinister: p,
dexter: q,
}
}
#[inline]
pub fn sinister(self) -> P {
self.sinister
}
#[inline]
pub fn dexter(self) -> Q {
self.dexter
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Disiunctio<P, Q> {
Sinister(P),
Dexter(Q),
}
impl<P, Q> Disiunctio<P, Q> {
#[inline]
pub fn sinister(p: P) -> Self {
Disiunctio::Sinister(p)
}
#[inline]
pub fn dexter(q: Q) -> Self {
Disiunctio::Dexter(q)
}
#[inline]
pub fn elimina<R, F, G>(self, f: F, g: G) -> R
where
F: FnOnce(P) -> R,
G: FnOnce(Q) -> R,
{
match self {
Disiunctio::Sinister(p) => f(p),
Disiunctio::Dexter(q) => g(q),
}
}
}
#[derive(Debug, Clone, Copy)]
pub struct Finitus<N: Naturalis, Bound: Naturalis> {
_n: PhantomData<N>,
_bound: PhantomData<Bound>,
}
impl<N: Naturalis + Minor<Bound>, Bound: Naturalis> Finitus<N, Bound> {
pub fn new() -> Self {
Finitus {
_n: PhantomData,
_bound: PhantomData,
}
}
}
impl<N: Naturalis + Minor<Bound>, Bound: Naturalis> Default for Finitus<N, Bound> {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::dependent::peano::{N1, N2, N3, N5, Zero};
#[test]
fn congruentia_lifts_equality_through_a_constructor() {
struct OptionWitness;
impl crate::typeclasses::hkt::HKT for OptionWitness {
type Target<T> = Option<T>;
}
let proof: Aequalitas<i32, i32> = Aequalitas::reflexio();
let _lifted: Aequalitas<Option<i32>, Option<i32>> = proof.congruentia::<OptionWitness>();
}
use alloc::string::ToString;
#[test]
fn test_testimonium_non_nihil() {
let _proof: Testimonium<N2, IsNonNihil> = testimonium();
let _proof2: Testimonium<N5, IsNonNihil> = testimonium();
}
#[test]
fn test_testimonium_minor() {
let _proof: Testimonium<N2, IsMinor<N5>> = testimonium();
let _proof2: Testimonium<Zero, IsMinor<N1>> = testimonium();
}
#[test]
fn test_testimonium_maior() {
let _proof: Testimonium<N5, IsMaior<N2>> = testimonium();
let _proof2: Testimonium<N3, IsMaior<Zero>> = testimonium();
}
#[test]
fn test_testimonium_aequus() {
let _proof: Testimonium<N3, IsAequus<N3>> = testimonium();
let _proof2: Testimonium<Zero, IsAequus<Zero>> = testimonium();
}
#[test]
fn test_aequalitas_reflexio() {
let _proof: Aequalitas<N3, N3> = reflexio();
let _proof2: Aequalitas<i32, i32> = reflexio();
}
#[test]
fn test_aequalitas_symmetria() {
let proof: Aequalitas<N3, N3> = reflexio();
let _symmetric: Aequalitas<N3, N3> = proof.symmetria();
}
#[test]
fn test_aequalitas_transitivitas() {
let p1: Aequalitas<N3, N3> = reflexio();
let p2: Aequalitas<N3, N3> = reflexio();
let _transitive: Aequalitas<N3, N3> = p1.transitivitas(p2);
}
#[test]
fn test_decisio() {
let yes: Decisio<i32> = Decisio::Ita(42);
assert!(yes.is_ita());
assert!(!yes.is_non());
assert_eq!(yes.expect("Decisio::Ita(42) should hold a value"), 42);
let no: Decisio<i32> = Decisio::Non;
assert!(no.is_non());
assert!(!no.is_ita());
}
#[test]
fn test_existentia() {
let exists = Existentia::new(42i32, "proof");
assert_eq!(exists.fst(), 42);
assert_eq!(exists.snd(), "proof");
}
#[test]
fn test_coniunctio() {
let conj = Coniunctio::new(1, "two");
assert_eq!(conj.sinister(), 1);
assert_eq!(conj.dexter(), "two");
}
#[test]
fn test_disiunctio() {
let left: Disiunctio<i32, &str> = Disiunctio::sinister(42);
let result = left.elimina(|n| n.to_string(), std::string::ToString::to_string);
assert_eq!(result, "42");
let right: Disiunctio<i32, &str> = Disiunctio::dexter("hello");
let result2 = right.elimina(|n| n.to_string(), std::string::ToString::to_string);
assert_eq!(result2, "hello");
}
#[test]
fn test_finitus() {
let _bounded: Finitus<N2, N5> = Finitus::new();
let _bounded2: Finitus<Zero, N3> = Finitus::new();
}
#[test]
fn test_propositio() {
assert!(Verum::VALUE);
}
}