use crate::abstraction::*;
use core::ops::*;
#[derive(Clone, Copy, Debug)]
pub struct Prop(bool);
pub mod constructors {
use super::Prop;
pub const fn from_bool(b: bool) -> Prop {
Prop(b)
}
pub fn and(lhs: Prop, other: Prop) -> Prop {
Prop(lhs.0 && other.0)
}
pub fn or(lhs: Prop, other: Prop) -> Prop {
Prop(lhs.0 || other.0)
}
pub fn not(lhs: Prop) -> Prop {
Prop(!lhs.0)
}
pub fn eq<T>(_lhs: T, _rhs: T) -> Prop {
Prop(true)
}
pub fn ne<T>(_lhs: T, _rhs: T) -> Prop {
Prop(true)
}
pub fn implies(lhs: Prop, other: Prop) -> Prop {
Prop(lhs.0 || !other.0)
}
pub fn forall<A, F: Fn(A) -> Prop>(_pred: F) -> Prop {
Prop(true)
}
pub fn exists<A, F: Fn(A) -> Prop>(_pred: F) -> Prop {
Prop(true)
}
}
impl Prop {
pub const fn from_bool(b: bool) -> Self {
constructors::from_bool(b)
}
pub fn and(self, other: impl Into<Self>) -> Self {
constructors::and(self, other.into())
}
pub fn or(self, other: impl Into<Self>) -> Self {
constructors::or(self, other.into())
}
pub fn not(self) -> Self {
constructors::not(self)
}
pub fn eq(self, other: impl Into<Self>) -> Self {
constructors::eq(self, other.into())
}
pub fn ne(self, other: impl Into<Self>) -> Self {
constructors::ne(self, other.into())
}
pub fn implies(self, other: impl Into<Self>) -> Self {
constructors::implies(self, other.into())
}
}
impl Abstraction for bool {
type AbstractType = Prop;
fn lift(self) -> Self::AbstractType {
Prop(self)
}
}
pub trait ToProp {
fn to_prop(self) -> Prop;
}
impl ToProp for bool {
fn to_prop(self) -> Prop {
self.lift()
}
}
impl From<bool> for Prop {
fn from(value: bool) -> Self {
Prop(value)
}
}
impl<T: Into<Prop>> BitAnd<T> for Prop {
type Output = Prop;
fn bitand(self, rhs: T) -> Self::Output {
Prop(self.0 & rhs.into().0)
}
}
impl<T: Into<Prop>> BitOr<T> for Prop {
type Output = Prop;
fn bitor(self, rhs: T) -> Self::Output {
Prop(self.0 | rhs.into().0)
}
}
impl Not for Prop {
type Output = Prop;
fn not(self) -> Self::Output {
Prop(!self.0)
}
}
pub fn forall<T, U: Into<Prop>>(f: impl Fn(T) -> U) -> Prop {
constructors::forall(|x| f(x).into())
}
pub fn exists<T, U: Into<Prop>>(f: impl Fn(T) -> U) -> Prop {
constructors::exists(|x| f(x).into())
}
pub fn implies(lhs: impl Into<Prop>, rhs: impl Into<Prop>) -> Prop {
constructors::implies(lhs.into(), rhs.into())
}
pub use constructors::eq;