Created
December 21, 2020 17:15
-
-
Save Shirataki2/894ebd54e80c156d37bb83b456377cec to your computer and use it in GitHub Desktop.
実用性 無になってしまった気がするけど供養
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pub mod base { | |
pub trait Zero: Sized { | |
fn zero() -> Self; | |
fn is_zero(&self) -> bool; | |
} | |
pub trait One: Sized { | |
fn one() -> Self; | |
fn is_one(&self) -> bool; | |
} | |
pub trait Inv: Sized { | |
type Output; | |
fn inv(&self) -> Self::Output; | |
} | |
pub trait Signed: Sized { | |
fn abs(&self) -> Self; | |
fn abs_sub(&self, other: &Self) -> Self; | |
fn is_positive(&self) -> bool; | |
fn is_negative(&self) -> bool; | |
} | |
pub trait Unsigned: Sized {} | |
pub trait Bounded: Sized { | |
fn min_value(&self) -> Self; | |
fn max_value(&self) -> Self; | |
} | |
macro_rules! integer_primitives { | |
($($t: tt)*) => {$( | |
impl Zero for $t { | |
fn zero() -> Self { 0 } | |
fn is_zero(&self) -> bool { self == &0 } | |
} | |
impl One for $t { | |
fn one() -> Self { 1 } | |
fn is_one(&self) -> bool { self == &1 } | |
} | |
impl Bounded for $t { | |
fn min_value(&self) -> Self { std::$t::MIN } | |
fn max_value(&self) -> Self { std::$t::MAX } | |
} | |
)*}; | |
} | |
macro_rules! signed_int_primitives { | |
($($t: tt)*) => {$( | |
impl Signed for $t { | |
fn abs(&self) -> Self { if self >= &0 { *self } else { -self } } | |
fn abs_sub(&self, other: &Self) -> Self { if self >= other { self - other } else { other - self } } | |
fn is_positive(&self) -> bool { self > &0 } | |
fn is_negative(&self) -> bool { self < &0 } | |
} | |
)*}; | |
} | |
macro_rules! unsigned_int_primitives { | |
($($t: tt)*) => {$( | |
impl Unsigned for $t {} | |
)*}; | |
} | |
macro_rules! floating_primitives { | |
($($t: tt)*) => {$( | |
impl Zero for $t { | |
fn zero() -> Self { 0.0 } | |
fn is_zero(&self) -> bool { self == &0.0 } | |
} | |
impl One for $t { | |
fn one() -> Self { 1.0 } | |
fn is_one(&self) -> bool { self == &1.0 } | |
} | |
impl Signed for $t { | |
fn abs(&self) -> Self { if self >= &0.0 { *self } else { -self } } | |
fn abs_sub(&self, other: &Self) -> Self { (self - other).abs() } | |
fn is_positive(&self) -> bool { self > &0.0 } | |
fn is_negative(&self) -> bool { self < &0.0 } | |
} | |
impl Bounded for $t { | |
fn min_value(&self) -> Self { std::$t::MIN } | |
fn max_value(&self) -> Self { std::$t::MAX } | |
} | |
)*}; | |
} | |
integer_primitives!(u128 u64 u32 u16 u8 usize i128 i64 i32 i16 i8 isize); | |
signed_int_primitives!(i128 i64 i32 i16 i8 isize); | |
unsigned_int_primitives!(u128 u64 u32 u16 u8 usize); | |
floating_primitives!(f32 f64); | |
} | |
pub mod common { | |
use std::ops::*; | |
use super::base; | |
pub trait Elem: Sized + Copy + Clone + PartialEq {} | |
impl<T: Sized + Clone + Copy + PartialEq> Elem for T {} | |
pub trait Magma: Elem + Add<Output=Self> {} | |
impl<T: Elem + Add<Output=Self>> Magma for T {} | |
pub trait Associative: Magma {} | |
impl<T: Magma> Associative for T {} | |
pub trait SemiGroup: Magma + Associative {} | |
impl<T: Magma + Associative> SemiGroup for T {} | |
pub trait Monoid: SemiGroup + base::Zero {} | |
impl<T: SemiGroup + base::Zero> Monoid for T {} | |
pub trait ComMonoid: Monoid + AddAssign + PartialOrd {} | |
impl<T: Monoid + AddAssign + PartialOrd> ComMonoid for T {} | |
pub trait Group: Monoid + Neg<Output=Self> {} | |
impl<T: Monoid + Neg<Output=Self>> Group for T {} | |
pub trait AbelGroup: ComMonoid + Group {} | |
impl<T: Group + ComMonoid> AbelGroup for T {} | |
pub trait SemiRing: ComMonoid + Mul<Output=Self> + base::One {} | |
impl<T: ComMonoid + Mul<Output=Self> + base::One> SemiRing for T {} | |
pub trait Ring: AbelGroup + SemiRing {} | |
impl<T: AbelGroup + SemiRing> Ring for T {} | |
pub trait ComRing: Ring + MulAssign {} | |
impl<T: Ring + MulAssign> ComRing for T {} | |
pub trait Field: ComRing + Div<Output=Self> + DivAssign {} | |
impl<T: ComRing + Div<Output=Self> + DivAssign> Field for T {} | |
} | |
#[cfg(test)] | |
mod tests { | |
use super::base::*; | |
use super::common::*; | |
use std::ops::*; | |
trait Sum { | |
type Output; | |
fn sum(&self) -> Self::Output; | |
} | |
#[derive(PartialEq, Copy, Clone)] | |
struct GCD<T: ComMonoid>(T); | |
impl<T: ComMonoid> Zero for GCD<T> { | |
fn zero() -> Self { GCD(T::zero()) } | |
fn is_zero(&self) -> bool { self.0.is_zero() } | |
} | |
impl<T: ComMonoid + Rem<Output=T>> Add for GCD<T> { | |
type Output = GCD<T>; | |
fn add(self, rhs: Self) -> Self { | |
let mut x = self.0.clone(); | |
let mut y = rhs.0.clone(); | |
while y > T::zero() { | |
let r = x % y; | |
x = y; | |
y = r; | |
} | |
Self(x) | |
} | |
} | |
struct MonoidList<T: Monoid>(Vec<T>); | |
impl<T: Monoid> Sum for MonoidList<T> { | |
type Output = T; | |
fn sum(&self) -> T { | |
self.0.iter().fold(T::zero(), |acc, &x| acc + x) | |
} | |
} | |
#[test] | |
fn test_1() { | |
let v: MonoidList<GCD<u32>> = MonoidList(vec![GCD(18), GCD(12), GCD(36)]); | |
assert_eq!(v.sum(), GCD(6)); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment